JDK 17 used for coding!
Switch Statement Overview
A switch statement is:
- a decision-making structure with a single value being evaluated. The flow is redirected to the first matching branch: the case statement.
- a cleaner approach to a combination of if or else statements when making decisions based on a single value.
Syntax:
switch (expressionToTest) {
case constantExpression1:
//branch for case1
break; //optional break
case constantExpression2, constantExpression3:
//branch for case2 and case3
default: //optional default
//default branch
}
ExpressionToTest should be an expression that resolves to one of the switch supported types:
- int and Integer
- byte and Byte
- short and Short
- char and Character
- String
- enum values
- var if the type resolves to one of the preceding types
We can’t pass the null values as an argument to a switch statement.
For strings, the switch operator utilizes the equals() method under the hood, allowing it to accurately compare a String argument with a String case value.
ConstantExpression must be a compile-time constant value of the same data type as the switch value. This means we can use only:
- literals
- enum constants
- final constant variables of the same data type. Final constant in the context of a switch means that the variable is marked final and initialized with a literal value when declared.
final int getNumber() { return 4; }
public void checkNumbers() {
final int n1 = 1;
int n2 = 2;
int n3 = 3;
final int n4 = getNumber();
switch (n3) {
case n1:
case n2: //DOES NOT COMPILE
case this.getNumber(): //DOES NOT COMPILE
case n4: //DOES NOT COMPILE
case 2 + 2:
}
}
Switch Statement Rules
- If no case statement is matched, the code within the default statement will be executed if it is present.
- The break statement is used to exit the switch block preventing subsequent case statements from being evaluated. If there is no break statement, the control will fall through to the next case and subsequent code blocks will be executed until a break statement is encountered or the end of the switch block is reached.
If-else to switch statement example
A classic switch example is printing the day of the week. Let’s start with using if and else statements:
public void printDayOfWeek(int day) {
if (day == 1) {
System.out.println("Monday");
} else if (day == 2) {
System.out.println("Tuesday");
} else if (day == 3) {
System.out.println("Wednesday");
} else if (day == 4) {
System.out.println("Thursday");
} else if (day == 5) {
System.out.println("Friday");
} else if (day == 6) {
System.out.println("Saturday");
} else if (day == 7) {
System.out.println("Sunday");
}
}
Let’s rewrite this using a switch statement:
public void printDayOfWeek(int day) {
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
case 4:
System.out.println("Thursday");
break;
case 5:
System.out.println("Friday");
break;
case 6:
System.out.println("Saturday");
break;
case 7:
System.out.println("Sunday");
break;
default:
System.out.println("Invalid value");
}
}
The switch version with the same logic is definitely cleaner and easy to follow.
The case statements can be combined when you want to resolve multiple values to a single branch:
public void printActivityPerDays(int day) {
switch (day) {
case 1, 2, 3: //syntax available starting with Java 14
System.out.println("Mon to Wed: Going to Movie");
break;
case 4: case 5: case 6: //syntax prior to Java 14
System.out.println("Thu to Sat: Going to Theatre");
break;
case 7:
System.out.println("Sunday: Staying home");
break;
default:
System.out.println("Invalid value");
}
}
Switch Expression Overview
The switch expression was officially added to Java 14. This expression is a compact form of a switch statement, capable of returning a value. The switch expression supports two types of branches: an expression and a block.
Syntax:
/*optional result*/
int result = switch (expressionToTest) {
case constantExpression1 -> 2;
case constantExpression2, constantExpression3 -> {
//block of code
yield 20; //yield required if switch returns a value
}
default -> 30; //required only if all possible case values are not handled and a value is returned
};
Switch Expression Rules
- If we are returning a value from the switch expression, all case and default branches that do not throw an exception must return a data type that is compatible with the assignment. In this context, every branch that is a block must yield a value.
- A default branch is required unless all cases are covered when a value is returned from the switch expression. If no value is returned the default branch is optional.
In a switch expression, the break statement is not required after each case. Unlike a traditional switch statement, a switch expression automatically exits after executing the matched case, eliminating the need for explicit break statements.
The yield keyword is employed to return a value from the switch expression, particularly when the case statement is a block. It’s important to note that the code following a switch expression is executed, as yield doesn’t exit the method; rather, it solely returns a value from the switch.
Switch-statement to switch-expression example
Let’s rewrite our previous example using a switch expression:
public void printDayOfWeek(int day) {
String result = switch(day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> {
System.out.println("case 6 reached");
//any other code
yield "Saturday";
}
case 7 -> "Sunday";
default -> "Invalid value";
};
System.out.println(result);
}
We can see that a lot of boilerplate code was removed while keeping the same behavior.
Let’s rewrite our previous example which combined case statements using a switch expression:
public void printActivityPerDays(int day) {
switch(day) {
case 1, 2, 3 -> System.out.println("Mon to Wed: Going to Movie");
case 4, 5, 6 -> System.out.println("Thu to Sat: Going to Theatre");
case 7 -> System.out.println("Sunday: Staying home");
}
}
We removed the default branch to demonstrate that it is optional when no value is returned, even when all possible case values are not handled.
As stated in the switch expression rules section, if we return a value and don’t cover all possible cases we need a default statement. In the following example, the inclusion of a default case is necessary for the code to compile.
enum Level { LOW, MEDIUM, HIGH }
public void checkPlayerLevel(Level level) {
String playerLevel = switch (level) {
case LOW -> "Low level";
case MEDIUM -> "Medium level";
default -> "No level reached";
};
}
If we add a case for HIGH we don’t need a default statement anymore as we cover all possible values of enum Level.
If you use an enum containing three values and someone subsequently introduces a fourth value, any switch expressions relying on the enum without a default branch will experience compilation failures. If this becomes a common occurrence, addressing and rectifying such issues in your code may become a substantial task. Therefore, it is advisable to incorporate a default branch in every switch expression, including those dealing with enum values.
Conclusions
In conclusion, the switch statement and expression serve as valuable tools, offering efficient ways to handle multiple branches of code based on a given condition.
The switch expression is more concise than the switch statement and offers the possibility of assigning a value from the expression which is very useful.
Proper utilization of these constructs involves considering their specific use cases, such as handling enums or a limited number of options.
The complete code is available on GitHub.