Site iconJava PDF Blog

How to improve switch statements after Java 13

Improvements to the use of switch statements was first previewed in Java 12 with JEP-325. Some JEPs are released as previews to allow the community to provide feedback before the feature is released. Since Java 12 feedback has been reviewed and the switch statement improvements have been tweaked again.

Java 13 now has JEP-354 which supersedes JEP-325 and introduces some changes to the previous preview. For completeness this article will cover all of the switch improvements as of JEP-354, not just the improvements added since JEP-325.

The current state of switch statements

Switch statements are a fundamental of many languages and work in a similar way to if/else chains. Switch statements will likely be well known to many programmers, however some languages do not contain them. If you are not familiar with switches, here is a brief run down of how they currently function in Java.

A switch is a flow control statement that accepts a variable or expression which is compared from a series of cases, when a case is matched the code block for the case (the case statement) is executed.
For example

int number = 3;
switch(number % 2) {
case 0 :
System.out.println("Even");
break;
case 1 :
System.out.println("Odd");
break;
default :
System.out.println("Impossible");
}

The switch statement above accepts a number (but cound be almost any primitive data type) and checks the remainder of dividing the number by two against the case statements.
The cases 0 and 1 show output a message to the console to display if number if even or odd. The default option at the end is executed if no other case statement is matched, in this case it would never be executed.
Once a case is matched all case statements from that point onward is executed unless a break is added to stop execution, this is called fall through. Switch statements in Java also have the same scope for each case statement which can lead to complications if you are not careful.

JEP-354: Switch Expressions (Preview)

The intention of this JEP is to extend the current switch statements in 4 different ways.

Allow multiple constants per case separated by commas.

Switch statements currently allows cases to fall through to following cases, The examples below show the current and new approach.

//Current approach
switch(day) {
case MONDAY:
case TUESDAY:
System.out.println("First 2 days");
break;
case WEDNESDAY:
case THURSDAY:
System.out.println("Second 2 days");
break;
default:
System.out.println("Final 3 days");
}

//New approach using comma separated mutliple constants
switch(day) {
case MONDAY, TUESDAY:
System.out.println("First 2 days");
break;
case WEDNESDAY, THURSDAY:
System.out.println("Second 2 days");
break;
default:
System.out.println("Final 3 days");
}


Provide a new way of defining a case (without fall through).

Currently when defining a case statement we use case CONSTANT: which allows fall through to take place.
With the changes in JEP-354 we can define a case statement using case CONSTANT -> which does not allow fall through to take place.
The right hand side of the arrow can be an expression, a block or a throw statement. Thanks to this it ensures all variables declared will be inside a block and not in scope for the other case statements.
Below is an example of the new case statement type and the different approachs to the right hand side.

switch(day) {
case MONDAY, TUESDAY -> System.out.println("First 2 days");
case WEDNESDAY, THURSDAY -> {
System.out.println("Second 2 days");
}
default -> throw new RuntimeException("Final 3 days");
}


Allow switches to be used as a statement or an expression.

Switch statements are being extended to allow them to be used as an expression as well as a statement. A common use of a switch statement is to set a variable to different values based on the switch.
This would usually require the variable to be declared and then to set it within the switch. In order to stream line this and avoid potential errors a switch can return a value.
Using the new arrow approach mentioned in point 2 you can have a variable as the right hand value of a case which is then returned. See example below.

int numLetters = switch (month) {
case MAY -> 3;
case JUNE, JULY -> 4;
case MARCH, APRIL -> 5;
case AUGUST -> 6;
case JANUARY, FEBUARY, OCTOBER -> 7;
case NOVEMBER, DECEMBER -> 8;
case SEPTEMBER -> 9;
};


Introduce a new statements to yield a value when the switch is used as an expression.

With the introduction of the above 3 improvements a new statement has been introduced called yield.
Yield allows a value to be returned for a switch expression from case statements using the old style or the new style when using a code block.
This statement functions like a break that returns a value. its usage canbe seen below.

//New case statements
int numLetters = switch (month) {
case MAY -> 3;
case JUNE, JULY -> 4;
default -> {
final int length = month.toString().length();
yield length;
}
};

//Current case statements
int numLetters = switch (month) {
case JANUARY:
yield 7;
case FEBUARY:
yield 7;
default:
yield month.toString().length();
};

What benefits does this have?

The benefits of this change are more for the developers and less for the users of the applications written using these improvements.
The chagnes do not appear to offer improved performance or a feature that end users would directly interact with. All the benefits are purely for those writing code.
With the addition of case statements that prevent fall through and updates to scoping, potential issues with switches can be avoided. The changes also allow the code to be less verbose which leads to easier to understand code and prevents issues being masked by the visual noise.