Java 14 is going to be released on March 17, 2020. The new version of Java contains one major update to the Java language: new switch expressions. Let’s see how the new switch expressions can be used, what kind of advantages they offer, and what can potentially go wrong. In the end, you are going to find a tricky question about the switch expressions.

(the article has been published on Medium)

New Switch Expressions in Java 14

The classic switch statement

The current design of the switch statement in Java follows languages such as C and C++. It works only as a statement and supports fall through semantics by default. Here is an example of the classic switch statement with an enum:

You might have noticed many case and break statements in the example above. Those statements introduce some visual noise and make the code unnecessarily verbose. This visual noise may then mask mistakes such a missing break statement which would mean accidental fall through.

The new switch expressions

Java 14 extends switch so that it can be used as either a statement or an expression. In particular, the new Java introduces the following:

  • A new form of switch label case ... -> where only the code to the right of the label is going to be executed if the label is matched. The code to the right of a case ... -> label may be an expression, a block, or a throw statement.
  • A new yield statement to yield a value which becomes the value of the enclosing switch expression.
  • Multiple constants per case which are separated by commas.

With the new Java 14, it’s possible to use both traditional case … : labels and new case … -> labels. It is important that the traditional labels still support fall through by default, but the new ones don’t.

Let’s see how the example above can be re-written with the new switch expressions:

This simple example can be compiled and run with just a single command (thanks to JEP 330 which allowed launching single-file source-code programs since Java 11):

$ java WhoIsWho.java
Mozart was a composer
Dali was a painter
Dostoevsky was a writer

You can see that several case statements have been merged, and the code doesn’t use break statement any more. As a result, the print() method became much shorter and looks nicer. The following example shows a multiline default block which uses the new yield statement to yield a value. Note several new constants in the Person enum which are not covered by any case label in the switch expression:

Here is what it prints out:

$ java WhoIsWho.java
Mozart was a composer
Dali was a painter
Oops! I don't know about Einstein
Einstein was a …

The next example shows how factorial may be implemented with the new switch expressions:

Important details

There are several important things to know about the new switch expressions.

The first thing to know is that the cases of a switch expression must be exhaustive. In other words, for all possible values, there must be a matching switch label. Let’s just add a new element to the enum and see what’s going to happen:

Compilation will fail right away with the following error message:

$ java InvalidWhoIsWho.java
InvalidWhoIsWho.java:19: error: the switch expression does not cover all possible input values
         String title = switch (person) {
                        ^
1 error
error: compilation failed

Adding a simple default case makes the Java compiler happy:

In general, unless an enum is used and the cases of a switch expression cover all constants, a default clause is required in the switch expression.

The second thing to remember is that a switch expression must either complete normally with a value or by throwing an exception. Let’s take a look at the following code:

If we try to compile this code, the Java compiler will immediately complain:

InvalidSwitchExpressionWithoutDefault.java:8: error: the switch expression does not cover all possible input values
        return switch (n) {
               ^
1 error
error: compilation failed

Again, adding a default case makes it work:

The third important thing to keep in mind is that yield is now a restricted identifier. In particular, it means that classes named “yield” become illegal:

$ cat YieldClassName.java 
class yield {}
$ javac YieldClassName.java
YieldClassName.java:1: error: 'yield' not allowed here
class yield {
      ^
  as of release 13, 'yield' is a restricted type name and cannot be used for type declarations
1 error
error: compilation failed

However, it is allowed to use “yield” as a variable or a method name:

$ cat ValidUseOfYieldWord.java 
public class ValidUseOfYieldWord {
    void yield() {
        int yield = 0;
    }
}
$ javac ValidUseOfYieldWord.java && echo ok || echo failed
ok

Conclusion

Here is what the authors say about the new switch expressions:

These changes will simplify everyday coding

Let’s see.

Bonus

What do you think is going to happen? Here are the options:

  1. Compilation error.
  2. Runtime error.
  3. “Oops” is printed out.
  4. “OopsOops” is printed out
  5. “Forty-two” is printed out.

References