Switch expressions in Java 14 and later
Though perhaps not as traumatic as null pointer exceptions, Switch-Case fall-through has caused headaches for quite a few Java programmers. The fall-through can be convenient sometimes. Most of the time, though, it causes unexpected problems.
As a toy example, consider a little program that is supposed to tell us today’s date and how many days the current month has.
LocalDate today = LocalDate.now();
System.out.println("Today is " + today.toString());
Month month = today.getMonth();
int numberOfDays = 0;
switch (month) {
case JANUARY:
case MARCH:
case MAY:
case JULY:
case AUGUST:
case OCTOBER:
case DECEMBER:
numberOfDays = 31;
case FEBRUARY:
if (today.isLeapYear()) {
numberOfDays = 29;
} else {
numberOfDays = 28;
}
case APRIL:
case JUNE:
case SEPTEMBER:
case NOVEMBER:
numberOfDays = 30;
}
System.out.println("The month "
+ month.getDisplayName(TextStyle.FULL,
Locale.US) + " has "
+ numberOfDays + " days");
The output is going to be wrong more than half the year.
Today is 2025–01–03
The month January has 30 days
Clearly wrong. January hath 31 days, as it says in the Old Farmer’s Almanac. Not a big deal in a toy example. But it doesn’t take much imagination to see how Switch-Case fall-through could cause problems in a real world program.
Your integrated development environment (IDE), such as Apache NetBeans, is probably warning you about unused assignments.
If we just add Breaks after the lines with warnings, NetBeans will clear those warnings and our program should give the correct output.
Today is 2025–01–03
The month January has 31 days
But if your IDE is using Java 12 or 13 with preview features enabled, or Java 14 or later regardless of preview features, you might be getting one warning on the line with “switch (month)
”. In NetBeans, the warning says you can use a “rule switch.” Other IDEs might say that you can use a “switch expression.”
Switch expressions were added as a preview feature in Java 12, were kept in preview for Java 13 and officially adopted in Java 14.
NetBeans rewrote the Switch-Case above as shown below:
switch (month) {
case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER,
DECEMBER -> numberOfDays = 31;
case FEBRUARY -> {
if (today.isLeapYear()) {
numberOfDays = 29;
} else {
numberOfDays = 28;
}
}
case APRIL, JUNE, SEPTEMBER, NOVEMBER ->
numberOfDays = 30;
}
But we can do better than this. We can write something that almost feels like a Match-Case in Scala.
int numberOfDays = switch (month) {
case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER,
DECEMBER -> 31;
case FEBRUARY -> {
if (today.isLeapYear()) {
yield 29;
} else {
yield 28;
}
}
case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
};
Notice the use of curly braces and the reserved word yield
in the February case.
Switch expressions need to be exhaustive. If we were using 32-bit integers instead of the Month
enumerated type, we would be required to provide a Default case (using the enumerated type also spares us the worry of whether January is 0 or 1).
A lot of you reading this might still be using Java 8 for your professional work due to client requirements. But for your personal projects, it might be worthwhile to upgrade to a more recent Java version and avail yourself to features like Switch expressions.