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
:
- Statement with fallthrough
- Statement without fallthrough
- Expression with fallthrough
- 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? Preferswitch
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 usebreak
oryield
if you actually need fallthrough, or if you must add statements into aswitch
expression. These situations are exceedingly rare.
Next week, we’ll learn how to use enumerated types with switch
expressions.