JDK 14/JEP 305 instanceof Pattern Matching “Smart Casts”
I generally view the presence of the instanceof operator in Java code as a “red flag,” meaning that it’s not necessarily wrong to use instanceof
in certain situations, but its use sometimes indicates a design issue that could be resolved in a cleaner way as described in some resources referenced at the end of this post (including resources about similar type checking functionality in languages other than Java).
Although I’ve seen instanceof
used several times when it does not need to be, I’ve run into even more situations where it was not easy to avoid instanceof
. This is particularly true when working with legacy code bases and certain libraries and frameworks in which I have no ability to refactor relationships between classes to support interfaces, method overriding, and other tactics that can be used to remove the need for instanceof
.
A very common technique employed with instanceof
is to immediately cast to the type checked in the conditional using instanceof
. JEP 305 [“Pattern Matching for instanceof (Preview)”] provides an example of this common pattern and I’ve slightly adapted that example here:
1 2 3 4 5 | if (object instanceof String) { final String string = (String) object; // Do something with the 'string' variable typed as String } |
Benji Weber has posted on using reflection and on using lambda expressions to achieve Kotlin-like “instanceof smart casts.” Fortunately, JDK 14 and JEP 305 bring built-in language support (albeit preview status) for this approach.
JDK 14 introduces a preview feature that allows the instanceof
conditional and associated cast to be implemented completely within the conditional. The effect on the above code example is shown next:
1 2 3 4 | if (object instanceof String string) { // Do something with the 'string' variable typed as String } |
This preview feature is available in the JDK 14 Early Access Builds and I’m using JDK 14 Early Access Build 34 for my examples in this post.
The JEP 305 preview feature in JDK 14 is a small nicety whose advantage is more obvious in lengthy if
–then
–else
conditional statements. The next two code listings provide a comparison of the “old way” of calling instanceof
and explicitly casting to the “new preview way” of using instanceof
pattern matching.
Traditional instanceof
Coupled with Explicit Cast
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | static void makeAnimalNoises( final Object animal) { if (animal instanceof Dog) { final Dog dog = (Dog) animal; out.println(dog.bark()); } else if (animal instanceof Cat) { final Cat cat = (Cat) animal; out.println(cat.meow()); } else if (animal instanceof Duck) { final Duck duck = (Duck) animal; out.println(duck.quack()); } else if (animal instanceof Horse) { final Horse horse = (Horse) animal; out.println(horse.neigh()); } else if (animal instanceof Cow) { final Cow cow = (Cow) animal; out.println(cow.moo()); } else if (animal instanceof Lion) { final Lion lion = (Lion) animal; out.println(lion.roar()); } else { out.println( "ERROR: Unexpected animal: " + animal); } } |
JDK 14/JEP 305 Preview Feature
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | static void makeAnimalNoises( final Object animal) { if (animal instanceof Dog dog) { out.println(dog.bark()); } else if (animal instanceof Cat cat) { out.println(cat.meow()); } else if (animal instanceof Duck duck) { out.println(duck.quack()); } else if (animal instanceof Horse horse) { out.println(horse.neigh()); } else if (animal instanceof Cow cow) { out.println(cow.moo()); } else if (animal instanceof Lion lion) { out.println(lion.roar()); } else { out.println( "ERROR: Unexpected animal: " + animal); } } |
The full code is on GitHub and the difference between the old approach and new preview approach is available.
Because instanceof
pattern matching is a preview feature, the code using this feature must be compiled with the javac flags --enable-preview
and -source 14
. It must be executed with java flag --enable-preview
.
Conclusion
For more details on how this feature is implemented, see the post “RFR: JDK-8237528: Inefficient compilation of Pattern Matching for instanceof.” Pattern matching support for instanceof
is another Amber-provided step toward reduced boilerplate code in Java.
Resources on Issues Using instanceof
- Java ‘instanceOf’: Why And How To Avoid It In Code
- Do you really need instanceof?
- Is using instanceof in Java consider bad practice?
- Using Instanceof Is Mostly a Code Smell
- Instanceof in Conditionals: A Code Smell
- Beware of instanceof Operator
- How Evil is ‘instanceof’?
- Type check is a code smell
Published on Java Code Geeks with permission by Dustin Marx, partner at our JCG program. See the original article here: JDK 14/JEP 305 instanceof Pattern Matching “Smart Casts” Opinions expressed by Java Code Geeks contributors are their own. |