1. 背景
Java中switch的语法长期被人诟病,尤其在scala中强大的case关键字对于类型匹配、顺序匹配、对象深度匹配、正则匹配、函数式的支持衬托下,更显得相形见拙。
因此对于switch的改造在很早的时候就提上日程了,终于到了Java 12中,switch的新表达式作为preview feature交付了。
2. 功能描述
作为preview feature,默认情况下是无法编译的,需要通过JVM参数enable-preview打开preview feature。
- 使用 javac --enable-preview --release 编译
- 使用 java --enable-preview 执行
2.1 fall-through语义的改进
长期以来,Java switch语句的设计遵循C和cpp语言,并默认支持fall-through语义。虽然这种传统恩控制流通常用于编写低级代码。但是由于switch用于更高级的上下文,它变得非常容易出错,如下面的示例
switch (letter) {
case "A":
case "B":
case "C":
System.out.println("ABC");
break;
case "D":
System.out.println("D_1");
break;
case "E":
case "F":
System.out.println("EF");
break;
case "G":
System.out.println("G_1");
break;
default:
System.out.println("DEFAULT");
break;
}
在Java 12中,可以被优化为下面的样式
switch (letter) {
case "A", "B", "C" -> System.out.println("ABC");
case "D" -> System.out.println("D_1");
case "E", "F" -> System.out.println("EF");
case "G" -> System.out.println("G_1");
default -> System.out.println("DEFAULT");
}
显然的,Java 12中的样式更加接近于业务逻辑。
2.2 赋值
有时候,我们使用switch语句是为了根据不同的分支赋值,如下面的代码
int i = 0;
switch (letter) {
case "A":
case "B":
case "C":
i = 1;
break;
case "D":
i = 2;
break;
case "E":
case "F":
i = 3;
break;
case "G":
i = 4;
break;
default:
i = 5;
break;
}
System.out.println("test2_1 i=" + i);
在Java 12中,可以被优化为下面的样式
int i = switch (letter) {
case "A", "B", "C" -> 1;
case "D" -> 2;
case "E", "F" -> 3;
case "G" -> 4;
default -> 5;
};
System.out.println("test2 i=" + i);
2.3 break with value
int i = switch (letter) {
case "A", "B", "C" -> {
break 1;
}
case "D" -> {
break 2;
}
case "E", "F" -> {
break 3;
}
case "G" -> {
break 4;
}
default -> {
break 5;
}
};
System.out.println("test3 i=" + i);
通常的,"case L ->"或"case L :"switch标签后面紧跟着一个语句,但是如果跟着个代码块,并希望代码块返回值,则需要是用break with value语义。
3. 总结
总得来说,在传统的switch case控制流之外,Java 12添加了"case L ->"switch标签,这一改动也遵循着Java 8以来Java语言发展的方向,即让程序员能编写出更容易阅读的代码,这种代码更多地表达了业务逻辑,而不是从机制上如何实现,易读的代码也易于维护、更可靠、更不容易出错。
4. 参考资料
JEP 325: Switch Expressions (Preview)
https://openjdk.java.net/jeps/325