JEP 441, Pattern Matching for switch, has been promoted from Targeted to Completed for JDK 21. This JEP finalizes this feature and incorporates enhancements in response to feedback from the previous four rounds of preview: JEP 433, Pattern Matching for switch (Fourth Preview), delivered in JDK 20; JEP 427, Pattern Matching for switch (Third Preview), delivered in JDK 19; JEP 420, Pattern Matching for switch (Second Preview), delivered in JDK 18; and JEP 406, Pattern Matching for switch (Preview), delivered in JDK 17. This feature enhances the language with pattern matching for switch
expressions and statements.
Pattern matching for switch
is a significant leap from the traditional switch
statements and expressions. The feature allows patterns to appear in case
labels, relaxes the historical null-hostility of switch
, and enhances safety by requiring pattern switch
statements to cover all possible input values.
Pattern matching was first introduced to the instanceof
operator in Java 16 (JEP 394), which enabled the operator to take a type pattern and perform pattern matching. This extension simplified the instanceof-and-cast idiom, making it more concise and less error-prone. Consider the following snippets:
// Prior to Java 16
if (obj instanceof String) {
String s = (String)obj;
// use s
}
// As of Java 16
if (obj instanceof String s) {
// use s
}
With JDK 21, this pattern matching has been extended to switch
expressions and statements, allowing them to work on any type and permitting case labels with patterns rather than just constants. Consider the following snippets:
// As of Java 21
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}
Notably, this release also integrates the null
test into the switch
by allowing a new null
case label. This change reduces the boilerplate code and potential errors in handling null
selector expression values. Consider the following snippets:
// As of Java 21
static void testFooBarNew(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
};
}
The new switch
pattern matching also introduces when
clauses in switch
blocks specify guards to pattern case labels, referred to as guarded case
labels.
// As of Java 21
static void testStringOld(String response) {
switch (response) {
case null -> { }
case String s when s.equalsIgnoreCase("YES") -> System.out.println("You got it");
case String s when s.equalsIgnoreCase("NO") -> System.out.println("Shame");
case String s -> System.out.println("Sorry?");
}
}
The concept of a when
clause suggests that it would be used to provide additional conditions that must be met for the case
statement to match beyond just the pattern match. If the condition in the when
clause evaluates to true, the case
label will apply. However, this is speculation based on the information available, and with specific examples and documentation, the exact usage is still being determined.
JEP 441 also extends the treatment of enums, allowing qualified names of enum constants to appear as case constants. This feature can be used when switching over an enum type. To maintain compatibility with existing Java code, when switching over an enum type, a case constant can still use the simple name of a constant of the enum type being switched over.
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("Weekday");
case SATURDAY, SUNDAY -> System.out.println("Weekend");
}
Looking ahead, the OpenJDK team has outlined several potential enhancements that could further expand pattern-matching capabilities in Java. These include the addition of AND and OR patterns, which would provide more expressivity for case
labels with patterns. There's also the possibility of directly supporting guarded patterns as a special pattern form, allowing for more complex conditional logic within the switch
statement. Another exciting prospect is the potential for general classes to declare deconstruction patterns, specifying how they can be matched against. These enhancements would continue to push the boundaries of what's possible with pattern matching in Java, making the language even more powerful and flexible for developers.
Developers who want to learn more can refer to this InfoQ article which shares a comprehensive guide for pattern matching in Java.
Developers who want to experiment with these new features can download the OpenJDK from the JDK 21 Early-Access Builds.
Another alternative is to use SDKMan, a software development kit manager, to download and manage different versions of Java. SDKMan can be used via the command line, making the process easier for developers who prefer this method.
However, these are early-access builds, so they may not be as stable as the final release, scheduled for September 2023, and are intended for testing and feedback purposes.