Java 12 - Switch Expressions (JEP 325)
One of the very interesting enhancements in Java 12 is: the extension of switch statement so that it can be used either as a statement or as an expression (JEP 325). Both forms (as a statement or as an expression) can use either a "traditional" or "simplified" scoping and control flow behavior. These changes will simplify everyday coding, and also prepare the way for the use of pattern matching (JEP 305) in switch. This feature is a preview language feature.
Let's check TraditionalSwitchCase.java which contain's the 'old' way of doing switch statement:
public class TraditionalSwitchCase {
public static void main(String[] args) {
getGrade('A');
getGrade('C');
getGrade('D');
getGrade('E');
getGrade('X');
}
public static void getGrade(char grade) {
switch (grade) {
case 'A':
System.out.print("Excellent");
break;
case 'B':
System.out.print("Good");
break;
case 'C':
System.out.print("Standard");
break;
case 'D':
System.out.print("Low");
break;
case 'E':
System.out.print("Very Low");
break;
default:
System.out.print("Invalid");
break;
}
getResult(grade);
}
public static void getResult(char grade) {
switch (grade) {
case 'A':
case 'B':
case 'C':
System.out.println("::Success");
break;
case 'D':
case 'E':
System.out.println("::Fail");
break;
default:
System.out.println("::No result");
break;
}
}
}
New Switch Arrow-form
Java 12 introduced case L -> syntax that removes the need for break statements, because only the statements next to -> is executed. The new switch syntax can only be compiled (via javac) and run (via java) with --enable-preview flag.
Then, let's compare with JEP325NewSwitchCase.java which is a rewrite version of TraditionalSwitchCase.java using new-style syntax.
public class JEP325NewSwitchCase {
public static void main(String[] args) {
getGrade('A');
getGrade('C');
getGrade('D');
getGrade('E');
getGrade('X');
}
public static void getGrade(char grade) {
switch (grade) {
case 'A' -> System.out.print("Excellent");
case 'B' -> System.out.print("Good");
case 'C' -> System.out.print("Standard");
case 'D' -> System.out.print("Low");
case 'E' -> System.out.print("Very Low");
default -> System.out.print("Invalid");
}
getResult(grade);
}
public static void getResult(char grade) {
switch (grade) {
case 'A', 'B', 'C' -> System.out.println("::Success");
case 'D', 'E' -> System.out.println("::Fail");
default -> System.out.println("::No result");
}
}
}
Both version still produce same result:
Excellent::Success Standard::Success Low::Fail Very Low::Fail Invalid::No result
As we can see, the second version (JEP325NewSwitchCase.java) is shorter and simpler. The arrow-form, on the other hand, signifies that only the block to its right will be executed, which prevents fall-through. Another improvement is, before Java 12, each case contained a single label, but now a case can match against multiple labels.
Switch as An Expression
switch can be an expression, so it can have a value, or it can return a value:
int day = new Random().nextInt(7) + 1;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.printf("%d: %s%n", day, dayName);
This is a very interesting improvement. As we know, before Java 12 to get a value from switch statement, we need to either assign the result to a variable (then break) or the switch return the value immediately (return for a method that contains the switch statement). Now, the entire switch expression is evaluated and the result can be assigned to a variable.
New switch expression with break
New switch expression also can use a "traditional" switch block with colons (case L:). But with values are returned using the 'break' along with an argument:
public class JEP325SwitchCaseBreak {
public static void main(String[] args) {
getGrade('A');
getGrade('C');
getGrade('D');
getGrade('E');
getGrade('X');
}
public static void getGrade(char grade) {
System.out.print(switch (grade) {
case 'A':
break "Excellent";
case 'B':
break "Good";
case 'C':
break "Standard";
case 'D':
break "Low";
case 'E':
break "Very Low";
default:
break "Invalid";
});
System.out.println(getResult(grade));
}
public static String getResult(char grade) {
return switch (grade) {
case 'A', 'B', 'C':
break "::Success";
case 'D', 'E':
break "::Fail";
default:
break "::No result";
};
}
}
Maven Configuration to Enable Preview Flag
If you are using maven, and want to enable preview flag (--enable-preview), you can do it via maven-compiler-plugin.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dariawan</groupId>
<artifactId>java12-examples</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<inceptionYear>2019</inceptionYear>
...
<properties>
<java.version>1.12</java.version>
<maven.compiler.source>1.12</maven.compiler.source>
<maven.compiler.target>1.12</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
...
</properties>
<dependencies>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>12</release>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
...
</plugins>
</build>
</project>