12. Pattern Matching for instanceof
Pattern matching for instanceof (Java 16+) eliminates the redundant cast after a type check by introducing a binding variable that is already typed and in scope.
Explanation
Before Java 16, a type check and cast required two steps: if (obj instanceof String) { String s = (String) obj; ... }. Pattern matching combines them: if (obj instanceof String s) { ... } โ s is automatically a String within the if block.
The binding variable is only in scope where the compiler can prove the pattern matched โ it is not in scope in the else branch. Negated patterns (!(obj instanceof String s)) make s available in the else/later code.
Pattern matching generalises in Java 21 to switch expressions (guarded patterns with when), record deconstruction patterns, and array patterns โ all built on this foundation.
Example
public class PatternMatchingInstanceof {
sealed interface Animal permits Dog, Cat, Bird {}
record Dog(String name) implements Animal {}
record Cat(String name) implements Animal {}
record Bird(String name, boolean canFly) implements Animal {}
static String describe(Object obj) {
// Old style (pre-Java 16): verbose and error-prone
// if (obj instanceof String) {
// String s = (String) obj; // redundant cast
// return "String: " + s.toUpperCase();
// }
// Pattern matching (Java 16+)
if (obj instanceof String s) {
return "String of length " + s.length() + ": " + s.toUpperCase();
} else if (obj instanceof Integer i && i > 0) {
// Guard condition in the same if
return "Positive integer: " + i;
} else if (obj instanceof Integer i) {
return "Non-positive integer: " + i;
}
return "Unknown: " + obj;
}
static String describeAnimal(Animal a) {
// Pattern matching switch (Java 21+)
return switch (a) {
case Dog d -> d.name() + " says Woof";
case Cat c -> c.name() + " says Meow";
case Bird b when b.canFly() -> b.name() + " can fly!";
case Bird b -> b.name() + " cannot fly";
};
}
public static void main(String[] args) {
System.out.println(describe("hello"));
System.out.println(describe(42));
System.out.println(describe(-5));
System.out.println(describeAnimal(new Dog("Rex")));
System.out.println(describeAnimal(new Bird("Penguin", false)));
}
}Sources
- https://openjdk.org/jeps/394 โ JEP 394: Pattern Matching for instanceof
- https://openjdk.org/jeps/441 โ JEP 441: Pattern Matching for switch