Pattern Matching for Switch in Java
Pattern Matching for `switch` expressions and statements, a feature that has evolved through several preview versions, is now a standard feature in Java. This enhancement significantly improves the expressiveness and safety of `switch` blocks, allowing for more concise and readable code when dealing with different types or values.
Traditional `switch` vs. Pattern Matching `switch`
Before pattern matching, `switch` statements were primarily used with primitive types, enums, and `String`s. Handling different types often required a series of `if-instanceof` checks, which could be verbose and error-prone.
// Traditional way (pre-Java 17)
Object obj = 123L;
if (obj instanceof Integer) {
Integer i = (Integer) obj;
System.out.println("Integer: " + i);
} else if (obj instanceof String) {
String s = (String) obj;
System.out.println("String: " + s.length());
} else if (obj instanceof Long) {
Long l = (Long) obj;
System.out.println("Long: " + l);
} else {
System.out.println("Unknown type");
}
With pattern matching for `switch`, you can directly use type patterns in `case` labels, making the code much cleaner:
// Using pattern matching for switch (Java 17+)
Object obj = 123L;
String result = switch (obj) {
case Integer i -> "Integer: " + i;
case String s -> "String: " + s.length();
case Long l -> "Long: " + l;
case null -> "It's null!"; // Handling null explicitly
default -> "Unknown type";
};
System.out.println(result);
Key Features and Benefits
- Type Patterns: Directly match against types and automatically cast the matched value to a new binding variable (e.g., `case Integer i`).
- `null` Handling: Explicitly handle `null` cases within the `switch` block, improving null safety.
- Guarded Patterns: Add a `when` clause to a pattern to specify additional conditions (e.g., `case String s when s.length() > 5 -> ...`).
- Exhaustiveness Checking: The compiler can ensure that all possible cases are covered, reducing the likelihood of runtime errors (especially with sealed classes).
- Conciseness and Readability: Reduces boilerplate code and makes the logic clearer, especially for complex multi-type handling.
Guarded Patterns Example
Guarded patterns allow you to add a boolean expression to a `case` label, providing more fine-grained control:
public String process(Object o) {
return switch (o) {
case Integer i when i > 0 -> "Positive Integer: " + i;
case Integer i -> "Non-positive Integer: " + i;
case String s when s.length() > 10 -> "Long String: " + s;
case String s -> "Short String: " + s;
default -> "Something else";
};
}
Exhaustiveness with Sealed Classes
When combined with sealed classes, pattern matching for `switch` becomes even more powerful. The compiler can verify that all permitted subclasses of a sealed class are covered in the `switch` block, eliminating the need for a `default` clause if all cases are handled.
// Assuming Shape is a sealed class with Circle, Rectangle, Triangle
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double side1, double side2, double side3) implements Shape {}
public double getArea(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> {
// Heron's formula for triangle area
double s = (t.side1() + t.side2() + t.side3()) / 2;
yield Math.sqrt(s * (s - t.side1()) * (s - t.side2()) * (s - t.side3()));
}
};
}
In this example, if you were to remove one of the `case` labels (e.g., `case Triangle t`), the compiler would issue a warning or error, ensuring that your `switch` statement is exhaustive.
Conclusion
Pattern Matching for `switch` is a significant step forward in Java's evolution, making code more readable, concise, and robust. It simplifies common programming patterns and, when combined with other modern Java features like sealed classes, provides a powerful toolkit for building expressive and safe applications. Embracing this feature will lead to cleaner and more maintainable Java codebases.