8 Pattern Matching

Pattern matching involves testing whether an object has a particular structure, then extracting data from that object if there's a match. You can already do this with Java. However, pattern matching introduces new language enhancements that enable you to conditionally extract data from objects with code that's more concise and robust.

A pattern describes a test that can be performed on a value. Patterns appear as operands of statements and expressions, which provide the values to be tested. For example, consider this expression:

s instanceof Rectangle r

The pattern Rectangle r is an operand of the instanceof expression. It's testing if the argument s has the type given in the pattern, which is Rectangle. Sometimes, the argument that a pattern tests is called the target.

Note:

When the operand to the right of instanceof is a pattern, like the previous example, then instanceof is the pattern match operator.

When the operand to the right of instanceof is a type, then instanceof is the type comparison operator. The following example uses instanceof as the type comparison operator:

s instanceof Rectangle

A pattern can declare zero or more pattern variables. For example, the pattern Rectangle r declares only one, r.

The process of testing a value against a pattern is called pattern matching. If a value successfully matches a pattern, then the pattern variables are initialized with data from the target. In this example, if s is a Rectangle, then s is converted to a Rectangle and then assigned to r.

Patterns can also appear in the case labels of a switch statement or expression. For example:

public static double getArea(Shape s) throws IllegalArgumentException {
    switch (s) {
        case Rectangle r:
            return r.length() * r.width();
        case Circle c:
            return c.radius() * c.radius() * Math.PI;
        default:
            throw new IllegalArgumentException("Unrecognized shape");
    }
}

A type pattern consists of a type along with a single pattern variable. In this example, Rectangle r is a type pattern.

A record pattern consists of a record type and a (possibly empty) record pattern list. For example, consider this record declaration and expression:

record Point(double x, double y) {}
// ...

obj instanceof Point(double a, double b)

The record pattern Point(double x, double y) tests whether the target obj is a Point(double, double). If so, it extracts the x and y values from obj directly and assigns them to the pattern variables a and b, respectively.