1. Overview
In this quick tutorial, we'll continue our series on Java 14 by taking a look at Pattern Matching for instanceof which is another new preview feature included with this version of the JDK.
In summary, JEP 305 aims to make the conditional extraction of components from objects much simpler, concise, readable and secure.
2. Traditional instanceOf Operator
At some point, we've probably all written or seen code that includes some kind of conditional logic to test if an object has a specific type. Typically, we might do this with the instanceof operator followed by a cast. This allows us to extract our variable before applying further processing specific to that type.
Let's imagine we want to check the type in a simple hierarchy of animal objects:
if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.meow(); // other cat operations } else if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.woof(); // other dog operations } // More conditional statements for different animals
In this example, for each conditional block, we're testing the animal parameter to determine its type, converting it via a cast and declaring a local variable. Then, we can perform operations specific to that particular animal.
Although this approach works, it has several drawbacks:
- It's tedious to write this type of code where we need to test the type and make a cast for every conditional block
- We repeat the type name three times for every if block
- Readability is poor as the casting and variable extraction dominate the code
- Repeatedly declaring the type name means there's more likelihood of introducing an error. This could lead to an unexpected runtime error
- The problem magnifies itself each time we add a new animal
In the next section, we'll take a look at what enhancements Java 14 provides to address these shortcomings.
3. Enhanced instanceOf in Java 14
Java 14, via JEP 305, brings an improved version of the instanceof operator that both tests the parameter and assigns it to a binding variable of the proper type.
This means we can write our previous animal example in a much more concise way:
if (animal instanceof Cat cat) { cat.meow(); } else if(animal instanceof Dog dog) { dog.woof(); }
Let's understand what is happening here. In the first, if block, we match animal against the type pattern Cat cat. First, we test the animal variable to see if it's an instance of Cat. If so, it'll be cast to our Cat type, and finally, we assign the result to cat.
It is important to note that the variable name cat is not an existing variable, but instead a declaration of a pattern variable.
We should also mention that the variables cat and dog are only in scope and assigned when the respective pattern match expressions return true. Consequently, if we try to use either variable in another location, the code will generate compiler errors.
As we can see, this version of the code is much easier to understand. We have simplified the code to reduce the overall number of explicit casts dramatically, and the readability is greatly improved.
Moreover, this kind of type of test pattern can be particularly useful when writing equality methods.
4. Conclusion
In this short tutorial, we looked at Pattern Matching with instanceof in Java 14. Using this new built-in language enhancement helps us to write better and more readable code, which is generally a good thing.
As always, the full source code of the article is available over on GitHub.