In this article, we will look over the switch
keyword in Java and all the enhancements it has received up to JDK 17, including the switch expression.
1. What is a Switch Statement?
Switch is a selection statement that allows you to control the flow of the execution of your application. It works as a multi-branch statement and offers a better solution to consecutive if-else statements. The traditional switch
has been part of the Java language since its beginning and, therefore, it will work with any JDK version.
“The switch differs from the if in that switch can only test for equality, whereas if can evaluate any type of Boolean expression. That is, the switch looks only for a match between the value of the expression and one of its case constants.”
“A switch statement is usually more efficient than a set of nested ifs.”
Schildt, Herbert. Java the Complete Reference 12th Edition. McGraw Hill, 2022.
2. Java Switch Syntax
Up until Java 6, switch
statements only accepted five datatypes, namely: byte, short, int, char, or an enumeration (requires JDK 5 or above), and the traditional switch looks like this:
Bear in mind that an empty switch
block is valid, and that only two keywords are mandatory to have code inside the block: switch
and case
, all the others, such as break
and default
, are optional.
- Duplicated
case
values are not allowed in aswitch
statement. - The
case
value must be compatible with the expression. - All
case
values must be constants: literals or final variables. - The
break
statement is used to terminate theswitch
. - The
default
statement, if present, will be executed in case of no match. - If none of the cases is matched and there is no
default
statement, no code will run.
Now let’s see a Java switch example:
// Traditional Switch Statement private static void traditionalSwitch(int day) { switch (day) { case 1: System.out.println("Sunday"); break; case 2: System.out.println("Monday"); break; case 3: System.out.println("Tuesday"); break; case 4: System.out.println("Wednesday"); break; case 5: System.out.println("Thursday"); break; case 6: System.out.println("Friday"); break; case 7: System.out.println("Saturday"); break; default: System.out.println("Not a day"); } }
You can test this code by calling the traditionalSwitch(int day) method inside the main method passing any number you like.
traditionalSwitch(1); traditionalSwitch(5); traditionalSwitch(0);
Output:
Sunday Thursday Not a day
2.1 Java Switch Using Enums
Let’s rewrite the above code using enumerators which results in a more elegant and readable solution.
enum Weekdays { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
Now let’s add another method to switch between different values.
// Traditional Switch Using Enum private static void traditionalSwitchWithEnums(Weekdays weekday) { switch (weekday) { case SUNDAY: System.out.println(Weekdays.SUNDAY); break; case MONDAY: System.out.println(Weekdays.MONDAY); break; case TUESDAY: System.out.println(Weekdays.TUESDAY); break; case WEDNESDAY: System.out.println(Weekdays.WEDNESDAY); break; case THURSDAY: System.out.println(Weekdays.THURSDAY); break; case FRIDAY: System.out.println(Weekdays.FRIDAY); break; case SATURDAY: System.out.println(Weekdays.SATURDAY); break; } }
As you can see, apart from readability and the fact that now you must provide an enum
instead of any integer that could or could not be an option in the switch
, there isn’t much improvement over the previous version.
traditionalSwitchWithEnums(Weekdays.SUNDAY); traditionalSwitchWithEnums(Weekdays.TUESDAY); traditionalSwitchWithEnums(Weekdays.SATURDAY);
Output:
SUNDAY TUESDAY SATURDAYy
2.2 Multiple Cases without Break
There might be times when NOT having the break
statement is wanted. Consider the following short program:
// Multiple Cases without Break private static void multipleCasesWithoutBreak(Weekdays weekday) { switch (weekday) { case MONDAY: case TUESDAY: case WEDNESDAY: case THURSDAY: case FRIDAY: System.out.println("Workday"); break; case SATURDAY: case SUNDAY: System.out.println("Weekend"); break; } }
As you will see, by omitting the break
statement we can achieve the desired result.
multipleCasesWithoutBreak(Weekdays.MONDAY); multipleCasesWithoutBreak(Weekdays.SATURDAY);
Output:
Workday Weekend
2.3 Nested Switch Statements
It is possible to have a switch
inside a case
statement. A nested switch
defines its own block of code, so it is possible to have the very same literal or constant inside the nested switch
and conflicts shall emerge between them.
// Traditional Switch with Nested Switch private static void traditionalSwitchWithNestedSwitch(int firstExp, int secondExp) { switch (firstExp) { case 1: switch (secondExp) { case 1: case 3: System.out.println("Do this nested thing!"); break; // Break nested case 1 & 3 case 2: case 4: System.out.println("Do this other nested thing!"); break; // Break nested case 2 & 3 } break; // Without this break, case 2 will be executed every time. Comment it out and give it a run. case 2: System.out.println("You did not get into the nested switch!"); break; } }
It is important to add the break
statement after the closing switch curly bracket. Otherwise, the second case
will run every single time since it is not being broken. The nested break
statements have no effect on the outer ones.
traditionalSwitchWithNestedSwitch(1, 1); traditionalSwitchWithNestedSwitch(1, 2); traditionalSwitchWithNestedSwitch(2, 0);
Output:
Do this nested thing! Do this other nested thing! You did not get into the nested switch!
3. Java Switch JDK 7
Not being able to use String
in the switch
block has always been a complaint in the Java community and it finally arrived with JDK 7. A more than welcoming addition for the Java Developer Community.
// Traditional Switch with Strings private static void traditionalSwitchWithStrings(String weekday) { switch (weekday) { case "Sun": System.out.println("Sunday"); break; case "Mon": System.out.println("Monday"); break; case "Tue": System.out.println("Tuesday"); break; case "Wed": System.out.println("Wednesday"); break; case "Thu": System.out.println("Thursday"); break; case "Fri": System.out.println("Friday"); break; case "Sat": System.out.println("Saturday"); break; default: System.out.println("Not a day!"); } }
A nice-to-have-addition to the switch statement. Aside from the possibility of using String
datatype, not much has changed.
traditionalSwitchWithStrings("Sun"); traditionalSwitchWithStrings("Thu"); traditionalSwitchWithStrings("Weekend");
Output:
Sunday Thursday Not a day!
4. Java Switch JDK 14
Starting with JDK 14, many of the preview features introduced in JDK 12 and JDK 13 became a permanent part of the language. These were exciting features that have changed the way Java developers code.
4.1 Multiple case constants
From JDK 14 on, it is possible to queue constants in just one case
statement which allows for a much more elegant, and readable code.
// Traditional Switch with Constant List private static void traditionalSwitchWithConstantList(Weekdays weekday) { switch (weekday) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY: System.out.println("Workday"); break; case SATURDAY, SUNDAY: System.out.println("Weekend"); break; } }
If we compare this piece of code with our previous version of the same program, but without multiple case constants. Check chapter 2.2 for comparison. This code looks cleaner.
traditionalSwitchWithConstantList(Weekdays.MONDAY); traditionalSwitchWithConstantList(Weekdays.WEDNESDAY); traditionalSwitchWithConstantList(Weekdays.SATURDAY);
Output?
Workday Workday Weekend
4.2 Switch Can Now Return Values
From this point on, the traditional switch
statements can return values, and therefore they have become switch expressions.
Initially, the word break
would be used to return the value. This word got replaced in JDK 13 by the keyword yield
. Keep in mind that yield
will immediately terminate the switch
expression. It works like a return
keyword inside the switch
block.
Let’s see a practical example to better understand how this works.
enum Operation { ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION }
We have added an enum of basic mathematical operations.
// Switch Expression with Yield private static int switchExpressionWithYield(Operation operation, int num1, int num2) { return switch (operation) { case ADDITION: yield num1 + num2; case SUBTRACTION: yield num1 - num2; case MULTIPLICATION: yield num1 * num2; case DIVISION: yield num1 / num2; }; }
It is important to notice the use of a semi-colon right after the closing curly bracket. This is due to the switch
being used in an assignment or a return that requires a semi-colon to terminate.
System.out.println("Addition: " + switchExpressionWithYield(Operation.ADDITION, 10, 5)); System.out.println("Subtraction: " + switchExpressionWithYield(Operation.SUBTRACTION, 10, 5)); System.out.println("Multiplication: " + switchExpressionWithYield(Operation.MULTIPLICATION, 10, 5)); System.out.println("Division: " + switchExpressionWithYield(Operation.DIVISION, 10, 5));
Output:
Addition: 15 Subtraction: 5 Multiplication: 50 Division: 2
4.3 The Arrow Operator
Another super exciting feature added to switch
was the arrow case
which replaces the traditional colon case
. As you will see, the arrow makes our code more elegant and saves us a lot of code space. This addition brought flexibility to the switch
since you can directly invoke a method or even assign a value to a variable right after -> without having to worry about adding break
, which has been the cause of many bugs in the past due to the fall-through behavior of the switch
.
// Switch Expression with Arrow Case private static void switchExpressionWithArrowCase(Weekdays weekday) { switch (weekday) { case SUNDAY -> System.out.println(Weekdays.SUNDAY); case MONDAY -> System.out.println(Weekdays.MONDAY); case TUESDAY -> System.out.println(Weekdays.TUESDAY); case WEDNESDAY -> System.out.println(Weekdays.WEDNESDAY); case THURSDAY -> System.out.println(Weekdays.THURSDAY); case FRIDAY -> System.out.println(Weekdays.FRIDAY); case SATURDAY -> System.out.println(Weekdays.SATURDAY); } }
It is a huge improvement compared to the same code in Chapter 2.1. It is shorter, more readable, and it does look much better. There are important points to consider whenever using the arrow case
:
- The arrow case never falls through cases, therefore there is no need for the
break
keyword. - The arrow case provides a shorter way of providing
switch
expressions. - The arrow case must be followed by either an expression, a block
{}
or anException
.
switchExpressionWithArrowCase(Weekdays.SUNDAY); switchExpressionWithArrowCase(Weekdays.TUESDAY); switchExpressionWithArrowCase(Weekdays.SATURDAY);
Output:
SUNDAY TUESDAY SATURDAY
Keep in mind it is possible to combine the added features to produce even cleaner code. For instance, consider the code in chapter 2.2 which was later modified in 4.1.
// Switch Expression with Constant List private static void switchExpressionWithConstantList(Weekdays weekday) { switch (weekday) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("Workday"); case SATURDAY, SUNDAY -> System.out.println("Weekend"); } }
We won’t print the results here since they are identical to the previous versions. But feel free to try them all and have fun with it.
Finally, if you want to learn more about the arrow operator, or in other words, Lambda Expressions, you can read this article.
5. Java Switch JDK 17 LTS
By the time of the publication of this article Java 17 is the latest LTS (Long Term Support) version of Java and it brought some great improvements to the switch
as well.
5.1 Switch Pattern Matching
Although it is a preview feature and you may have to enable it, it really is one exciting piece of news. Before this addition, we either had to have a bunch of sequential ifs or if-elses.
// Switch Expression with Pattern Matching private static void switchExpressionWithPatternMatching(Object obj) { switch (obj) { // Uncommenting will cause the switch to fail since everything falls into Object. //case Object o -> System.out.println(o); case String str -> System.out.println(str); case Integer i -> System.out.println(i); case Double d -> System.out.println(d); case Boolean b -> System.out.println(b); case Weekdays weekday -> System.out.println(weekday); case null -> System.out.println("It's " + null); // Literal to avoid ambiguity. default -> System.out.println("Not an expected type!"); }; }
With pattern matching, for each case, we check whether the object is an instanceof
a particular class. Primitives are not allowed here, so you must provide a class, a generic class, or an array.
switchExpressionWithPatternMatching("String"); switchExpressionWithPatternMatching(0); switchExpressionWithPatternMatching(0.0); switchExpressionWithPatternMatching(true); switchExpressionWithPatternMatching(Weekdays.FRIDAY); switchExpressionWithPatternMatching(null); switchExpressionWithPatternMatching(new int[3]);
Output:
String 0 0.0 true FRIDAY It's null Not an expected type!
5.2 Switch Null Case
Before Java 17, switch
would throw a NullPointerException
if the value passed was null
. It still is the case today if you are not using matching patterns that allow for null cases. Now we can have a case for null values as well. As it has been demonstrated in the previous example, we won’t show any code snippets here.
5.3 Switch Guarded Pattern
Another powerful addition to the switch
was the guarded pattern which before was only possible using ifs or if-elses. It makes it possible to use the &&
operator in a case
. By the time of the publication of this article, the first operator must be &&
(double ampersand). Should you need to use more clauses, then you can use ||
, &
or |
.
// Switch Expression with Guarded Pattern private static void switchExpressionWithGuardedPattern(Object email) { switch (email) { case String s && s.contains("@") && s.length() > 8 -> login(); case null -> throw new IllegalArgumentException(); default -> System.out.println("Please enter a valid e-mail."); } } private static void login() { System.out.println("Registration successful!"); }
Bear in mind that Guarded Pattern only works with Pattern Matching.
switchExpressionWithGuardedPattern("[email protected]"); switchExpressionWithGuardedPattern("you_code.com"); switchExpressionWithGuardedPattern(null);
Output:
Registration successful! Please enter a valid e-mail. Exception in thread "main" java.lang.IllegalArgumentException at com.youlearncode.Main.switchExpressionWithGuardedPattern(Main.java:66) at com.youlearncode.Main.main(Main.java:59)
6. Conclusion
By now you should have a thorough understanding of the Java switch
, its evolution throughout Java history, and all the improvements brought by every version of Java, including preview features. You can also read here about if-else statements as they are an alternative to switch expressions. Finally, you can find the source code on our GitHub Page.