2 min read

Pattern Matching Using the instanceof Operator in Java

Pattern matching using instanceof allows you to define pattern variables, simplifies code, and avoids ClassCastExceptions.
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.