Java Pattern Matching: InstanceOf (JEP 305)

Apr 05, 2020
Last Updated: Nov 14, 2023
Java Pattern Matching: InstanceOf (JEP 305)
This new feature in Java 14 allows you to simplify your code and get rid of a lot of boilerplate when using instanceof.

instanceof

To better understand this new feature, let's look into how instanceof operator works. If you are already familiar with it, feel free to skip to the next section.

In short, it tests whether the given object is of the given type. Based on this, it returns either true or false.

    if(animal instanceof Cat) {
      // It is a cat! Do something
    } else {
      // It is not a cat, do something else
    }

This returns true if your object is of the given type or its subtype. Otherwise, it returns false.

Pattern matching for instanceof

The good old way

Consider the following example. Animal is a class which has two subclasses: Cat and Dog.

public String getAnimalSound(Animal animal) {
    if(animal instanceof Cat) {
        Cat cat = (Cat)animal;
        return cat.meow();
    } else if (animal instanceof Dog) {
        Dog dog = (Dog)animal;
        return dog.bark();
    }

    throw new UnknownAnimalException();
}

We get an animal as an input. If that animal is an instance of Cat, we want to get that cat to meow. If it is a dog, we need it to bark. Since these methods are not on Animal class, but rather on its subclasses, we need to:

  1. First, check what type of animal we have using instanceof.
  2. Create a new variable of type Cat or Dog.
  3. Cast our animal to the proper type.

Now we can use our cat or dog. Variation of this can be pretty common.

The code does its job, but it is unnecessarily verbose. We usually want to do all the steps above. The casting is unnecessary as we already checked with instanceof that we have either Cat or Dog.

Fortunately, Java 14 introduced a new feature called Pattern matching for instanceof described in JEP 305. It is currently a preview feature, so it may change in a future release.

The better way

In Java 14, the example above can be simplified.

// Before Java 14
if(animal instanceof Cat) {
    Cat cat = (Cat)animal;
    return cat.meow();
}

//After
if(animal instanceof Cat cat) {
    return cat.meow();
}

Here's what changed:

  1. No need to declare cat variable, it is available for us.
  2. There is no casting. We can use the cat as if it was of type Cat.
  3. The scope of thecat variable is only inside the if block.

This is simpler, more concise, easier to read, and less error-prone.

Variable scope

As already mentioned, the scope of the variable is only limited to the if block:

if(animal instanceof Cat cat) {
    return cat.meow();
} else {
    // Can't use cat here
}
// Can't use cat here either

However, you can use the variable inside the if condition, if you have more complicated conditions, such as with AND/OR.

if(animal instanceof Cat cat && cat.isAlive()) {
    return cat.meow();
}

After checking instanceof, after &&, we can use the cat variable already typed as Cat, not Animal.

IDEA Support

The good news is that there is good support for this feature in IntelliJ IDEA, introduced in version 2020.1 (along with support for other Java 14 new features, such as Records or Enhanced Switch)

IDEA pattern matching instanceof

UPDATE: Java 15

In Java 15, this feature is still present as a preview feture - JEP 375: Pattern Matching for instanceof (Second Preview). Although there is a new JEP for it, there are no changes relative to the Java 14 version.

Also new in Java 14




Let's connect