Going Beyond Java 8: Pattern Matching for instanceof
A developer and Java expert gives an overview of the instanceof operator in the recent versions of Java and how it can be used to improve your code.
Join the DZone community and get the full member experience.Join For Free
According to some surveys, like JetBrains's great survey, Java 8 is currently the most used Java version, despite being a 2014 release.
This article is the first in a series of articles titled, "Going Beyond Java 8," inspired by the contents of my book "Java for Aliens." These articles will guide the reader step-by-step to explore the most important features introduced starting with Java 9. The aim is to make the reader aware of how important it is to move forward from Java 8, explaining the enormous advantages that the latest versions of the language offer.
In this article, we will look at an interesting novelty introduced in Java 14 as a preview feature (see related article). This is the first part of a complex feature known as pattern matching. It will affect various programming constructs in the future, for now, though, pattern matching is only available for use with the
instanceof operator as a feature preview. This will radically change the way we use this operator.
instanceof binary operator, like comparison operators, returns a boolean value. The peculiarity of this operator is that it uses a reference as the first operand, and a complex type as the second operand. It returns
true, if at runtime, the reference (which defines the first operand) points to an object instantiated by the type (which defines the second operand). It returns
true, even if the reference points to an object instantiated by a subclass of the type specified with the second operand. If one of these two conditions is not met, the
instanceof operator returns
Suppose we want to create a system that establishes the salaries of employees of a company, considering the following classes:
Suppose we have to pay the salaries to all types of employees, we could begin to group all the employees of the company within a heterogeneous collection:
To manage employee salary, we could create the following method:
This uses the
instanceof operator to test which type the polymorphic parameter
emp is pointing to and set the salary accordingly.
Now we can call this method within a
foreach loop (with 180 iterations), passing all of the elements of the heterogeneous collection, and thus reach our goal:
In the previous example, we observed that the
instanceof operator allows us to test to which type of instance a reference points. However, we already know that a superclass reference pointing to an object instantiated by a subclass cannot access the members declared in the subclass. For example, suppose a programmer's salary depends on the number of years of experience. In this situation, after testing that the reference
emp points to a
Programmer instance, we will need to access the
yearsOfExperience variable. If we tried to access it using the syntax:
we would get a compile-time error:
In fact, the reference
emp, being of the
Employee type, will not be able to access the methods that are declared in the subclasses. To overcome this obstacle, we can use the object cast mechanism. In practice, we must declare a
Programmer type reference and make it point to the memory address where the reference
emp points, using the cast to confirm the pointing range. The new reference, being of the
Programmer type, will allow us to access any member of the
The cast of objects uses a syntax very similar to the cast between primitive data:
Note that we are now able to access the encapsulated variable
In Figure 1, we ideally outline the situation with a graphical representation, where the object is pointed to by the
emp reference and the
Figure 1. Two different types of access to the same object
In Figure 1, the two references point to the same object, but with a different pointing range. It is essential to use the object cast only after checking its validity with the
instanceof operator. In fact, the compiler cannot determine if a certain object resides at a certain address instead of another. It is only at runtime that the Java Virtual Machine can use the
instanceof operator to resolve any doubts.
What's the Problem?
The combined use of the
instanceof operator and the object cast cannot be defined as a Java best practice, but it is certainly a well-known and widely used programming pattern. What is evident, however, is that this practice is undoubtedly verbose. It is also repetitive; in the previous example we named the
Programmer type three times in two lines. Finally, after a test with
instanceof, the next statement is obviously assumed to be a cast. In fact, some IDEs allow us to automate this practice. However, if we do not automate the coding with an IDE, we may end up doing a lot of copy-and-pasting if this code is repeated several times, and this could also imply a
ClassCastException at runtime.
Pattern Matching for
Java 14 introduced the first part of a complex feature known as pattern matching as a feature preview. In this feature, a pattern (not to be confused with a design pattern) is composed of:
- a predicate: a test that looks for the matching of an input with its operand.
- one or more binding variables; these are extracted from the operand depending on the test result.
A pattern is therefore defined as a synthetic way of expressing a complex solution.
When this feature is fully implemented, it will also affect other topics such as
record types, and the
switch construct. In version 15, pattern matching is still presented as a feature preview, and the only part implemented concerns the pattern that involves the
instanceof operator and the object cast that we have just seen. In practice, by enabling the feature preview, we can use an alternative syntax:
This syntax specifies a
pro, alongside the
instanceof operation. This reference can be used immediately, and no cast is required, since it is already a
Programmer-type reference. The syntax is therefore very simple, but some observations must be made.
In particular, the
pro reference is defined as a binding variable. Binding variables are particular local variables with a new type of constrained scope that depend on the pattern. Like a local variable, it can coexist with instance variables with the same identifier. The difference consists in the fact that its scope depends on the result of the predicate, i.e. if the result of the
instanceof test is
false. In the previous example, the
pro reference was visible only in the code block relating to the
if construct. If we added the
else clause, and prefixed the NOT operator to the
instanceof test in the following way:
pro reference would be visible only in the code block of the
else clause, and not in the
if code block.
Also, a binding variable is implicitly
final, and its addressing cannot be changed. For example, the following
would cause the below compile-time error:
This is currently the behavior of binding variables in Java 15, where pattern matching for
instanceof is still a feature preview. But in version 16 to be released in March 2021, pattern matching for
instanceof will be formalized as a standard Java feature and this limitation should be permanently removed.
In any case, through a binding variable (since it is a reference) it is still possible to change the internal state of the object it points to. For example, the following code is valid:
In fact, a new address is not assigned to the
proreference, but only a method is invoked on it.
At present, the final evolution of pattern matching for
instanceof is not yet fully defined, and other changes could be made. When we get a chance to test the standard version of this feature, we will come back to update this article.
In this article we have seen how Java 14 introduced pattern matching for
instanceof as a feature preview. This new feature introduces a new type of scope for binding variables, and will forever change the way we use the
instanceof operator and object cast. In Java 15, this feature is still in preview, but in version 16, thanks to the feedback received from users, there will be changes.
The pattern matching for
instanceof, therefore, represents another small step forward for the language.
Even ignoring the increased security offered by the latest versions of the JDK, there are plenty of reasons to upgrade your knowledge of Java, or at least your own Java runtime installations. My book "Java for Aliens," which inspired the "Going Beyond Java 8" series, contains all the information you need to learn Java from scratch, and uses a well-tested teaching method that has been perfected over 20 years of experience, which makes learning simple and exciting. It is also structured to deepen the topics and have superior knowledge that can make a difference to your career.
Published at DZone with permission of Claudio De Sio Cesari. See the original article here.
Opinions expressed by DZone contributors are their own.