If you’ve ever written code in a C-family programming language, you’re probably familiar with the switch statement. It provides a way to evaluate an expression against a series of case clauses. It’s like an if...else statement, except it’s best used to check multiple possible values for the same expression. In his book Core Java, Cay S. Horstmann explains that there have been four forms of switch since Java 14. Two of them are switch statements while the other two are switch expressions.

To demonstrate the four forms of switch, we’ll use an example I borrowed from the Oracle docs. We have an int variable numLetters and a String variable day. Using a switch, we want to assign the number of letters in day to numLetters.

switch statements

switch statement with fallthrough

This is the form of switch I’m familiar with from JavaScript. It dates back to C and suffers from the error-prone fallthrough behaviour. If you omit a break statement, execution falls through to the next case clause. This continues until a break statement is found.

In this example, we use the fallthrough behaviour to our advantage. The strings "Monday", "Friday", and "Sunday" all have 6 letters, but for "Monday" only, we want to print the string "It's Monday!" before assigning numLetters to a value. Because the case clause for "Monday" has no break statement, execution falls through to the case clause for "Friday" and "Sunday".

int numLetters = 0;
String day = "Monday";

switch (day) {
case "Monday":
System.out.println("It's Monday!");
case "Friday", "Sunday":
numLetters = 6;
break;
case "Tuesday":
numLetters = 7;
break;
case "Thursday", "Saturday":
numLetters = 8;
break;
case "Wednesday":
numLetters = 9;
break;
default:
numLetters = -1;
}

System.out.println(numLetters);

switch statement without fallthrough

As I said, the fallthrough behaviour is error-prone. Horstmann explains that you can compile your code with the -Xlint:fallthrough option to trigger warnings about the fallthrough behaviour. You can then use the @SuppressWarnings("fallthrough") annotation to annotate intentional usage of the fallthrough behaviour.

However, it may be safer to use a switch statement without the fallthrough behaviour. In this form of switch, notice that the case labels end with arrows (->) instead of colons (:). To group multiple statements in a case clause, you have to use curly braces ({}).

int numLetters = 0;
String day = "Monday";

switch (day) {
case "Monday" -> {
System.out.println("It's Monday!");
numLetters = 6;
}
case "Friday", "Sunday" ->
numLetters = 6;
case "Tuesday" ->
numLetters = 7;
case "Thursday", "Saturday" ->
numLetters = 8;
case "Wednesday" ->
numLetters = 9;
default ->
numLetters = -1;
}

System.out.println(numLetters);

switch expressions

switch expression with fallthrough

Permanently added to the language in Java 14, switch expressions are forms of switch that yield a value. You can then assign a variable to that value, for example. This first form of switch expression maintains the fallthrough behaviour. The case labels end with colons (:) and you use the yield keyword to yield values from the case clauses.

String day = "Monday";

int numLetters = switch (day) {
case "Monday":
System.out.println("It's Monday!");
case "Friday", "Sunday":
yield 6;
case "Tuesday":
yield 7;
case "Thursday", "Saturday":
yield 8;
case "Wednesday":
yield 9;
default:
yield -1;
};

System.out.println(numLetters);

switch expression without fallthrough

This is my favourite form of switch. If a case clause only contains the value to be yielded, you can omit the yield keyword and place the value directly after the arrow (->). If the case clause needs to contain statements, you have to put them in curly braces ({}) and use the yield keyword to yield the value for the clause.

String day = "Monday";

int numLetters = switch (day) {
case "Monday" -> {
System.out.println("It's Monday!");
yield 6;
}
case "Friday", "Sunday" -> 6;
case "Tuesday" -> 7;
case "Thursday", "Saturday" -> 8;
case "Wednesday" -> 9;
default -> -1;
};

System.out.println(numLetters);

Summary

Since Java 14, there have been four forms of switch:

  1. Statement with fallthrough
  2. Statement without fallthrough
  3. Expression with fallthrough
  4. Expression without fallthrough

The forms with the fallthrough behaviour use colons (:) to end the case labels. The forms without the fallthrough behaviour use arrows (->). You can’t mix and match both types in a single switch.

Regarding which form you should prefer, Horstmann writes:

With so many variations of switch, which one should you choose? Prefer switch expressions over statements. If each branch computes the value for a variable assignment or method call, yield the value with an expression, and then use it. … Only use break or yield if you actually need fallthrough, or if you must add statements into a switch expression. These situations are exceedingly rare.

Next week, we’ll learn how to use enumerated types with switch expressions.