Pattern Matching for switch
Pattern Matching for switch (JEP 441) is a game-changer feature in Java 21. It fundamentally upgrades the switch statement, which previously could only test for exact equality against a few types (enums, strings, integers).
Now, switch can test against Types, meaning it can replace long, complex chains of if-else statements.
The “If-Else” Problem
Traditionally, when you had an object and needed to perform different actions based on its specific class, you had to write a chain of checks. This pattern is often called “type testing”:
// The Old Way: Verbose and repetitive
static String formatter(Object obj) {
if (obj instanceof Integer i) {
return String.format("int %d", i);
} else if (obj instanceof Long l) {
return String.format("long %d", l);
} else if (obj instanceof Double d) {
return String.format("double %f", d);
} else if (obj instanceof String s) {
return String.format("String %s", s);
}
return obj.toString();
}
This code is hard to read because the logic (instanceof) is repeated, and it’s easy to miss a return or an else.
The Switch Solution
Verify 21 allows us to use patterns in case labels. We can match the type of the object directly in the switch.
// The Java 21 Way: Clean and Declarative
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
case null -> "null"; // We can now handle null too!
default -> obj.toString();
};
}
This isn’t just syntactic sugar—it’s safer. The compiler can now help check if your logic makes sense.
New Feature: Handling Null
A historical pain point of switch was that it would throw a NullPointerException immediately if the variable tested was null.
In Java 21, you can write case null! This allows you to handle the “no value” scenario right alongside your other logic, without needing a separate if (obj == null) check before the switch.
Refined Patterns with when
Sometimes, matching the Type isn’t enough. You might want to match “A String, but only if it has length 1”.
In the past, you’d have to use a broad case String s and then put an if inside it. Now, you can use the when keyword (called a “guard”) to refine your match.
static void testBox(Object obj) {
switch (obj) {
// Matches IF it is a String AND the length is 1
case String s when s.length() == 1 -> System.out.println("Single char string");
// Matches all other Strings
case String s -> System.out.println("String");
// Fallback for everything else
default -> System.out.println("Other");
}
}
Essential Rules
- Order Matters: Java checks cases from top to bottom. You must put more specific cases (like the
Stringwithwhenlength is 1) before general cases (plainString). If you don’t, the compiler will warn you that the code is “dominated” (unreachable). - Completeness: If you are using a switch expression (assigning it to a variable or returning it), you must cover all possible options. Usually, this means you need a
defaultcase to handle “everything else”.
Pattern Matching for switch brings Java closer to modern functional languages, making code safer, shorter, and more expressive.