Today, I would like to take a look at Java statements and their evolution, and how you can use them more effectively in Java 17+.
This is a classic use case of how you can use statements in Java. You do not need to cover all possible cases. If you want to handle only one case, you need to use the break
keyword to end the case statement.
public void switchOption(Integer option){
switch (option) {
case 1:
System.out.println("Case 1");
break;
case 2:
System.out.println("Case 2");
break;
default:
System.out.println("Default");
}
}
Switch statement as a return value
There you can see how to use switch if you need return value
public void switchOptionAsReturnValue(Integer option){
String result = switch (option) {
case 1 -> "Case 1";
case 2 -> "Case 2";
default -> "Default";
};
System.out.println(result);
}
Yield statment in switch expression
The yield
statement helps differentiate between switch statements and switch expressions. A switch statement, unlike a switch expression, can be the target of a break
statement. Conversely, a switch expression, unlike a switch statement, can be the target of a yield
statement.
public void switchWithYieldStatement(Month month){
int monthValue = switch (month) {
case Month.JANUARY -> {
System.out.println("January");
yield 1;
}
case Month.FEBRUARY -> {
System.out.println("February");
yield 2;
}
default -> throw new IllegalStateException("Unexpected value: " + Month.JANUARY);
};
}
Multiple options
You can use multiple options to group for each case.
public void switchMultipleOptions(Month month){
switch (month) {
case Month.JANUARY, Month.FEBRUARY, Month.MARCH -> System.out.println("First quarter");
case Month.APRIL, Month.MAY, Month.JUNE -> System.out.println("Second quarter");
case Month.JULY, Month.AUGUST, Month.SEPTEMBER -> System.out.println("Third quarter");
case Month.OCTOBER, Month.NOVEMBER, Month.DECEMBER -> System.out.println("Fourth quarter");
}
}
Arrow operator
you can also use the arrow operator (->
) in switch expressions to make the code more concise and readable.
public void switchOption2(Integer option) {
switch (option) {
case 1 -> System.out.println("Case 1");
case 2 -> System.out.println("Case 2");
default -> System.out.println("Default");
}
}
Pattern matching
When using pattern matching with an interface in a switch statement, it is necessary to include a default case.
public void switchPatternMatchingByInterface(Person person) {
switch (person) {
case Analyst a -> a.printJob();
case Manager m -> m.printJob();
case Programmer p -> p.printJob();
default -> throw new IllegalStateException("Unexpected value: " + person);
}
}
sealed classes allow you to restrict which other classes or interfaces can extend or implement them. This feature ensures that all possible subclasses are known at compile time, which allows for exhaustive pattern matching without requiring a default case.
Here’s a more detailed explanation:
- Sealed Classes and Interfaces: Introduced in Java 17, sealed classes and interfaces restrict the set of types that can extend or implement them. This is done by explicitly specifying the permitted subclasses or implementing classes.
- Pattern Matching: When you use pattern matching with sealed types, the compiler knows all possible subtypes. This allows the compiler to verify that all cases are covered in a switch statement or an if-else chain.
- Default Case: Because the compiler knows all possible subtypes, you don’t need to include a default case when pattern matching with sealed types. This is a significant advantage as it makes the code more robust and easier to maintain.
For more detail about sealed interface and sealed class you can find here
public void switchSealedInterface(ItPerson person) {
switch (person) {
case ItAnalys a -> a.printJob();
case ItManager m -> m.printJob();
case ItProgrammer p -> p.printJob();
}
}
and In the both cases you can see smart casting and how you can use methods of each object belong to interface or sealed interface
Conclusion
The article on Kotlin Server Squad discusses the evolution and usage of the Java switch statement, particularly in Java 17+. It covers classic switch statement use, returning values from switch expressions, utilizing the yield
statement, grouping multiple options, and using the arrow operator (->
). Additionally, it explores pattern matching with interfaces and sealed classes, highlighting how sealed types allow exhaustive pattern matching without a default case, improving code robustness and maintainability.