Switch Expressions 是在Project Amber下的Java 14中发布的。
Switch Expressions实际上是两个可以独立使用也可以组合使用的增强功能:
break
没有和贯穿fall-throughs的箭头符号- 用作
switch
带有返回值的表达式
让我们一一看一下变化(我使用的是JEP 361中的示例,稍作修改)。
初始点
在以下示例中,我们打印一周中给定日期的单词长度。对于最后两种情况,我编写的代码比必要的要复杂一些,以演示 switch 表达式的可能性。
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println((int) Math.pow(2, 3));
break;
case WEDNESDAY:
int three = 1 + 2;
System.out.println(three * three);
break;
}
由于所谓的“失败”(fall-throughs),即如果前一个案例没有以 break 语句终止,则在下一个案例中继续执行,这种表示法令人困惑且容易出错。
因此,Sonar、Checkstyle 和 PMD 等静态代码分析 (SCA) 工具将此类构造标记为代码异味:
使用箭头符号切换
以下示例显示使用箭头而不是冒号,从 Java 14 开始。以下规则适用:
- 在箭头之前,您可以列出几个用逗号分隔的案例。
- 箭头后面可以跟单个代码语句(第 2、3 和 4 行)或花括号中的代码块(第 5 到 8 行)。
break
在这种表示法中省略了语句。
以下是switch
箭头符号语句的示例代码:
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println((int) Math.pow(2, 3));
case WEDNESDAY -> {
int three = 1 + 2;
System.out.println(three * three);
}
}
像 IntelliJ 这样的现代 IDE 认识到了改进的潜力,并提供了自动转换为新格式的功能:
Switch 作为带有返回值的表达式
我们经常使用switch
将特定于案例的值分配给变量。在以下示例中,我们将其存储在numLetters
变量中,而不是打印工作日的长度:
(最后两个案例再次被有意冗长地写出来,以展示 switch 表达式的可能性。)
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = (int) Math.pow(2, 3);
break;
case WEDNESDAY:
int three = 1 + 2;
numLetters = three * three;
break;
default:
throw new IllegalStateException("Unknown day: " + day);
}
之后要使用该变量,我们必须——即使我们已经涵盖了每个工作日——要么事先初始化变量,要么指定一个默认情况。否则,编译器将中止并显示错误消息“Variable ‘numLetters’ might not have been initialized”。
从 Java 14 开始,我们可以将此语句转换为表达式。为此,我们使用 new 关键字返回每个值yield
。然后我们将 switch 表达式的结果直接赋值给变量:
int numLetters = switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
yield 6;
case TUESDAY:
yield 7;
case THURSDAY:
case SATURDAY:
yield (int) Math.pow(2, 3);
case WEDNESDAY:
int three = 1 + 2;
yield three * three;
default:
throw new IllegalStateException("Unknown day: " + day);
};
yield
是所谓的“上下文关键词”;switch
因此,它仅在表达式的上下文中才有意义。如果你yield
在源代码中使用了变量名——别担心;你仍然可以这样做。即使是这样的事情也是允许的:
int yield = 5; yield yield + yield;
箭头符号和switch表达式相结合
如果我们用箭头符号来写,刚才显示的 switch 表达式会变得更加优雅。我们可以写返回值
- 直接在箭头后面(第 2 行和第 3 行),
- 作为箭头后面的表达式或方法调用(第 4 行),
- 或
yield
从代码块(第 7 行)返回它。
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> (int) Math.pow(2, 3);
case WEDNESDAY -> {
int three = 1 + 2;
yield three * three;
}
default -> throw new IllegalStateException("Unknown day: " + day);
};
我们还可以让我们的 IDE 完成从传统的 switch 语句到带有箭头符号的 switch 表达式的完整重构:
枚举的完整性分析
由于变量 day 是一个枚举,编译器可以识别出我们已经涵盖了所有情况。因此,我们可以省略这种default
情况:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> (int) Math.pow(2, 3);
case WEDNESDAY -> {
int three = 1 + 2;
yield three * three;
}
};
我们的 IDE 也很乐意为我们这样做:
没有默认情况的表示法更短,有助于我们将来扩展枚举。如果我们扩展它——例如,通过NEWDAY
a——编译器会告诉我们 switch 表达式现在是不完整的:
所以 switch 表达式也可以让我们的代码更加健壮。
概括
switch表达式是一个强大的工具。箭头符号和用作具有返回值的表达式允许比以前更简洁且不易出错的符号。
Switch 表达式最初是在Java 12中作为预览功能引入的。在Java 13break
的第二个预览版中,最初用于返回值的关键字被替换为yield
. 在JDK Enhancement Proposal 361中,Switch Expressions 作为Java 14的最终功能发布,没有任何进一步的更改。