Pattern Matching for Switch in Java

Author By John Developer
May 20, 2025
Java Features
Pattern Matching for Switch

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.

Java
// 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:

Java
// 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

Guarded Patterns Example

Guarded patterns allow you to add a boolean expression to a `case` label, providing more fine-grained control:

Java
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.

Java
// 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.

Java Pattern Matching Switch Expressions Java 17
John Developer

John Developer

John is a senior Java developer with over 10 years of experience in enterprise application development. He is passionate about Java and enjoys exploring new features and best practices.