Pattern Matching for Switch in Java 21

Pattern matching for switch expressions and statements is a feature introduced in Java 21 that allows developers to match specific patterns within switch cases, making code more concise and readable.

To use pattern matching in a switch statement, we simply need to use the case keyword followed by a pattern. The pattern will be matched against the selector expression, and the corresponding code block will be executed if the match is successful.

In Java versions, the use of a switch statement was limited to a selector expression that only evaluated to a number, string or enum constant. Additionally, the case labels were required to be constants. However, in the release we can now use a switch statement or expression with a selector expression of any type. Have case labels that include patterns.

It enhancement means that a switch statement or expression can now check if its selector expression matches a pattern of just comparing it to a constant value. It allows for flexibility and expressiveness when it comes to controlling the flow of execution based on the value of the selector expression. For example:

PatternMatchingExample.java

Output:

obj is a String: Hello, world!

Selector Expression Type

The type of a selector expression can either be an integral primitive type or any reference type, such as in the previous examples. The following switch expression matches the selector expression obj with type patterns that involve a class type, an enum type, a record type, and an array type:

When Clauses

A when clause enables a pattern to be refined with a Boolean expression. A pattern label that contains a when clause is called a guarded pattern label, and the Boolean expression in the when clause is called a guard. A value matches a guarded pattern label if it matches the pattern and the guard evaluates to true. Consider the following example:

The following switch statement uses a when clause to match against a list of integers that contains at least one even number:

Pattern label dominance

Pattern label dominance in pattern matching in Java 21 is a mechanism that determines which case label in a switch statement should be executed when multiple patterns match the selector expression.

It's possible that many pattern labels could match the value of the selector expression. To help predictability, the labels are tested in the order that they appear in the switch block. In addition, the compiler raises an error if a pattern label can never match because a preceding one will always match first. The following example results in a compile-time error:

The following rules are used to determine pattern label dominance:

  • A pattern label dominates a constant label. For example, the pattern label case String s dominates the constant label case "hello".
  • A guarded pattern label dominates a constant label if the same pattern label without the guard does. For example, the pattern label case String s when s.length() > 1 dominates the constant label case "hello".
  • An unguarded pattern label dominates a guarded pattern label that has the same pattern. For example, the pattern label case String s dominates the pattern label case String s when s.length() > 0.
  • A guarded pattern label dominates another pattern label (guarded or unguarded) only when both the former's pattern dominates the latter's pattern and when its guard is a constant expression of value true.

If multiple patterns match the selector expression and none of the patterns dominate each other, the compiler will issue an error.

Type Coverage in switch Expressions and Statements

As describe in the switch expressions, the switch blocks of switch expressions and switch statements, which use pattern or null labels, must be exhaustive. It means that for all possible values, there must be a matching switch label. The following switch expression is not exhaustive and generates a compile-time error. Its type coverage consists of the subtypes of String or Integer, which doesn't include the type of the selector expression. For example:

HelloWorld.java

Output:

obj is a String

Scope of Pattern Variable Declarations

The scope of a pattern variable declaration is the part of the program where the pattern variable is accessible. The scope of a pattern variable declared in a switch statement is the switch block and any nested blocks within the switch block.

Here is an example of the scope of a pattern variable declaration in a switch statement:

PatternVariableScopeExample.java

Output:

The length of the string is: 12

Prior to this preview feature, switch expressions and switch statements threw a NullPointerException if the value of the selector expression is null. However, to add more flexibility, a null case label is available:

HelloWorld.java

Output:

obj is null

Parenthesized Patterns

A parenthesized pattern is a pattern surrounded by a pair of parentheses. Because guarded patterns combine patterns and expressions, we might introduce parsing ambiguities. We can surround patterns with parentheses to avoid these ambiguities, force the compiler to parse an expression containing a pattern differently, or increase the readability of code.

HelloWorld.java

Output:

obj is null





Latest Courses