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:
- First, check what type of animal we have using
instanceof
. - Create a new variable of type
Cat
orDog
. - 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:
- No need to declare cat variable, it is available for us.
- There is no casting. We can use the cat as if it was of type
Cat
. - The scope of the
cat
variable is only inside theif
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)
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.