Pattern Matching Using the instanceof Operator in Java
instanceof Operator
The instanceof operator is an expression that is used to check whether an instance is a specific type or not. It will return true if the instance is a specific type or false if it is not. An example of using instanceof to declare a boolean value is the following:
final Sting s = "";
// true
final boolean isString = s instanceof String;
Type Conversion
Before Java 17, when you were working with the instanceof operator, you would have to check the type and then cast it to that type. For example:
public void method(final Object object) {
if (object instanceof Integer) {
final Integer integer = (Integer) object;
// ...
} else if (object instanceof String) {
final String string = (String) object;
// ...
} else if (object instanceof Boolean) {
final Boolean bool = (Boolean) object;
// ...
}
}
This works, but a developer could still cast it to the wrong type. There isn't anything preventing the developer from doing the following:
if (object instanceof Integer) {
// ClassCastException: class java.lang.Integer
// cannot be cast to class java.lang.String
final String string = (String) object;
}
Pattern Variables
Pattern variables can be declared when using instanceof. This allows you to skip the type conversion since the variable declared will be the type you are checking. Pattern variables are declared after the type.
public void method(final Object object) {
if (object instanceof Integer integer) {
// ...
} else if (object instanceof String string) {
// ...
} else if (object instanceof Boolean bool) {
// ...
}
}
With this enhancement to Java, you should always use this and not cast in any different way when using instanceof. Even if there is only one usage of the variable that you need, you should still use this. This is guaranteed by the compiler that the pattern variable will be the expected type. This helps protect the code with refactors that could potentially introduce a ClassCastException.
Pattern Matching
You can perform pattern matching on pattern variables. After a pattern variable is declared, you can do something with it like the following:
final boolean isString =
object instanceof String string
&& !string.isEmpty();
There are times when you cannot use pattern matching with pattern variables. One case is using || in the following example.
final boolean isString =
object instanceof String string
|| !string.isEmpty();
Since the left hand side of the or is evaluated first, when it evaluates the right side of the or, the pattern variable isn't declared. This example would result in a compiler error.
Scope of Pattern Variables
The scope of a pattern variable will change depending on how you are using it. If you are using it like the following example, it will not be available after the statement.
final boolean isString =
object instanceof String string
&& !string.isEmpty();
When using a pattern variable in an if statement, it will have the same scope as the previous example as well as inside of the if block.
if (object instanceof String s && !s.isEmpty()) {
System.out.println(s);
}
Conclusion
Java 17 introduces the ability to use pattern matching using the instanceof operator. Using pattern variables, the compiler will ensure you are using the expected type, avoiding ClassCastExceptions and reducing potential future bugs.