I have a Java 17 project using Eclipse 2022-03 and OpenJDK 17:
openjdk 17.0.2 2022-01-18
OpenJDK Runtime Environment Temurin-17.0.2+8 (build 17.0.2+8)
OpenJDK 64-Bit Server VM Temurin-17.0.2+8 (build 17.0.2+8, mixed mode, sharing)
I'm trying to use the new Java 17 switch features, so I tried this in a method:
return switch(testEnum) {
case foo -> newFoo();
case bar -> newBar();
}
That works fine. But then I tried this (because the value might be null
):
return switch(testEnum) {
case foo -> newFoo();
case bar -> newBar();
case null -> newDefault();
}
Eclipse underlines null
in red and says:
Pattern Matching in Switch is a preview feature and disabled by default. Use --enable-preview to enable
Compiling via Maven produces:
[ERROR] /project/src/main/java/com/example/FooBar.java:[432,38] null in switch cases is a preview feature and is disabled by default.
[ERROR] (use --enable-preview to enable null in switch cases)
My Maven project has:
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
I know the compiler release setting isn't being ignored; otherwise it would be defaulting to Java 8 (as per my parent POM) and not allowing pattern matching at all.
Isn't null cases with pattern matching part of Java 17? What am I doing wrong?
Update: Pattern matching for switch
arrived in Java 21.
๐ switch
expressions != pattern matching with switch
You are mixing up the relatively new feature of switch
expressions with the still-not-released feature of pattern matching with switch
.
The switch
feature in Java has been evolving through 3 phases, two completed:
switch
statement (original feature in Java 1)switch
expression (Java 14+)switch
, including case null
(previewed in Java 17, 18, 19, & 20)switch
expressions with pattern matchingswitch
Understand that historically, the Java switch
statement has been hostile to null
checks. See this Question, How to use null in switch. As shown there, code such as this:
switch (i) {
case null:
doSomething0();
break;
}
โฆ was not possible.
switch
expressionsFast forward to Java 14, when switch
expressions was added to Java. See JEP 361: Switch Expressions. That allows the syntax seen in your first code example:
return switch(testEnum) {
case foo -> newFoo();
case bar -> newBar();
}
But read the JEP. No mention of null
โ ยซ crickets ยป.
switch
Fast forward further, to JEP 406: Pattern Matching for switch (Preview). Note that this is a preview feature in Java 17, not a final, officially released feature. (To understand how preview features work, read JEP 12: Preview Features.)
๐ In that JEP 406, notice its second goal: Allow the historical null-hostility of switch to be relaxed when desired.
Now search that page for โnullโ โย 73 hits! That page explains the former policy of the Java language:
Traditionally,
switch
statements and expressions throwNullPointerException
if the selector expression evaluates tonull
โฆ
Notice the mention of statements, the original switch
syntax, and additionally expressions, the new syntax used in your code. In both cases, null
check was forbidden.
That page goes on to explain the changes that motivate the inclusion of support for null checks. Read the JEP for will-written details.
๐ The upshot is that you can use case null
in a switch
in Java 17 โ but only if you go out of your way to enable the preview feature.
This feature arrived in Java 21. See JEP 441: Pattern Matching for switch.
Let's try this code example. Notice how we use plain old syntax here, without the ->
. The arrow operator is not related to our discussion here.
String x = null;
switch ( x )
{
case "starburst":
System.out.println( "Is starburst." );
break;
case null:
System.out.println( "Whoops, null." );
break;
default:
System.out.println( "Some other value found." );
break;
}