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:

TraditionalSwitchCase.java
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.

JEP325NewSwitchCase.java
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:

JEP325SwitchCaseBreak.java
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>