Pattern matching for switch

Core Java · lesson 30 of 42 · 4 min read

Switch on the type of a value, destructure a record, and narrow a case with when.

Open this lesson in the learning hub

Key points

  • Java 21 lets a case label be a type pattern: case Integer i -> ... tests and binds in one step.
  • A record pattern goes further: case Rect(double w, double h) pulls the components straight out.
  • Add a guard with when. The guarded label must be written before the plain one it narrows.
  • Labels are tested top to bottom, so a label that can never be reached is a compile error, not a silent bug.
  • case null is allowed. Without it a null selector still throws NullPointerException.
  • Over a sealed type the switch is exhaustive with no default, so a new subtype breaks the build.

Example

public class Main {

    sealed interface Shape permits Circle, Square, Rect {}

    record Circle(double r) implements Shape {}

    record Square(double side) implements Shape {}

    record Rect(double w, double h) implements Shape {}

    static String describe(Object o) {
        return switch (o) {
            case null -> "nothing at all";
            case Integer i when i < 0 -> "a negative int: " + i;
            case Integer i -> "an int: " + i;
            case String s -> "a string of " + s.length() + " chars";
            case Rect(double w, double h) when w == h -> "a square-ish rect " + w;
            case Rect r -> "a rect " + r.w() + " by " + r.h();
            default -> "something else: " + o.getClass().getSimpleName();
        };
    }

    // No default: the compiler knows Shape has exactly three permitted subtypes.
    static double area(Shape s) {
        return switch (s) {
            case Circle c -> Math.PI * c.r() * c.r();
            case Square q -> q.side() * q.side();
            case Rect(double w, double h) -> w * h;
        };
    }

    public static void main(String[] args) {
        Object[] values = {7, -3, "java", new Rect(2, 2), new Rect(2, 5), 4.5, null};
        for (Object o : values) {
            System.out.println(o + "  ->  " + describe(o));
        }

        System.out.printf("circle area %.2f, square area %.1f, rect area %.1f%n",
                area(new Circle(1)), area(new Square(3)), area(new Rect(2, 5)));
        System.out.println("the guarded case had to come first, or it could never be reached");
    }
}

Patterns collapse an instanceof-and-cast ladder into one exhaustive switch.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Core Java course, and every lesson in it is listed on the Core Java contents page.