Java: combined instance and casting?

(Please don't tell me that I should abstract X and add another method to it.)

In C ++, when I have an X variable of type X* and I want to do something specific, if it also has type Y* ( Y , which is a subclass of X ), I wrote this:

 if(Y* y = dynamic_cast<Y*>(x)) { // now do sth with y } 

The same seems impossible in Java (or is it?).

Instead, I read this Java code:

 if(x instanceof Y) { Y y = (Y) x; // ... } 

Sometimes, when you don't have the X variable, but instead it is a more complex expression, just because of this problem you need a dummy variable in Java:

 X x = something(); if(x instanceof Y) { Y y = (Y) x; // ... } // x not needed here anymore 

(It’s common that something() is iterator.next() . And there you see that you also cannot call it twice. You really need a dummy variable.)

You don’t need X here at all - you just have it because you cannot perform instanceof checking right away with the act. Compare this again with the fairly common C ++ code:

 if(Y* y = dynamic_cast<Y*>( something() )) { // ... } 

In this regard, I introduced the castOrNull function, which avoids the dummy variable X I can write this now:

 Y y = castOrNull( something(), Y.class ); if(y != null) { // ... } 

castOrNull implementation:

 public static <T> T castOrNull(Object obj, Class<T> clazz) { try { return clazz.cast(obj); } catch (ClassCastException exc) { return null; } } 

Now I have been told that using this castOrNull function castOrNull this way is an evil thing . Why is this? (Or to pose a more general question: would you agree and think that it is evil? If so, why so? Or do you think that this is a real (possibly rare) use case?)


As I said, I don’t want to discuss whether using such a lowering effect is a good idea. But let me briefly explain why I sometimes use it:

  • Sometimes I get into the case when I have to choose between adding a new method for a very specific thing (which will apply to only one subclass in one particular case) or using such an instanceof check. Basically, I have a choice between adding the doSomethingVeryVerySpecificIfIAmY() function or doing an instanceof check. And in such cases, I feel that the latter is cleaner.

  • Sometimes I have a collection of some interface / base class and for all entries of type Y , I want to do something and then remove them from the collection. (For example, I had a case where I had a tree structure and wanted to remove all child elements that are empty leaves.)

+6
java casting dynamic-cast instanceof
source share
5 answers

Now I have been told that using this castOrNull function in this way is evil. Why is this?

I can think of several reasons:

  • This is an opaque and tricky way to make something very simple. Unclear and tricky code is difficult to read, difficult to maintain, a potential source of errors (when someone does not understand it), and therefore evil.

  • The obscure and complex way in which the castOrNull method works most likely cannot be optimized by the JIT compiler. As a result, you will receive at least 3 additional method calls, as well as a lot of additional code to check the type and reflection. The unnecessary use of reflection is evil.

(In contrast, the simple way (with instanceof followed by the cast class) uses specific bytecodes for instanceof and class casting. Bytecode sequences can almost certainly be optimized so that there is no more than one null check and no more that one test an object type in native code. This is a generic template that should be easy for the JIT compiler to detect and optimize.)

Of course, “evil” is another way of saying that you REALLY should not do this.

None of your two added examples use the castOrNull method castOrNull either necessary or desirable. IMO, the “easy way” is better in terms of readability and performance.

+8
source share

In the most well-written / developed Java code, the use of instances and throws never occurs. With the addition of generics, many cast cases (and therefore instanceof) are not needed. They, at times, are still found.

The castOrNull method is evil in that you make Java code "unnatural." The biggest problem when switching from one language to another is the adoption of new language conventions. Temporary variables are very good in Java. In fact, all of your methods really hide the temporary variable.

If you find that you are writing a lot of throws, you should study your code and see why and look for ways to remove them. For example, if you add the getNumberOfChildren method, you can check if the node is empty and thus can trim it without casting (this assumption may not work for you in this case).

Generally speaking, there is "evil" in Java because they are usually not needed. Your method is more "evil" because it is not written as many people expected Java to be written.

Saying if you want to do this, go for it. This is actually not an “evil”, not a “right” way to do this in Java.

+5
source share

IMHO your castOrNull not evil, just meaningless. You seem obsessed with getting rid of the temporary variable and one line of code, while the question for me is more, why do you need so many drops in your code? In OO, this is almost always a sign of suboptimal design. And I would rather solve the root cause rather than consider the symptom.

+4
source share

I do not know exactly why a person said that it was evil. However, one of the reasons for their reasoning was that later you caught some kind of exception, and did not check before throwing. This is the way to do it.

 public static <T> T castOrNull(Object obj, Class<T> clazz) { if ( clazz.isAssignableFrom(obj.getClass()) ) { return clazz.cast(obj); } else { return null; } } 
+2
source share

Java exceptions are slow. If you are trying to optimize your performance by avoiding a double throw, you shoot in the foot using exceptions instead of logic. Never rely on catching an exception for something that you could reasonably check and fix (exactly what you are doing).

How slow are Java exceptions?

0
source share

All Articles