JEP 361 Switch 表达式
一、概要
扩展 switch,使其可以作为语句或表达式使用,以及使两种形式都可以使用传统的 case … : 标签(具有穿透效果)或新的 case … -> 标签(没有穿透效果),并添加一个新的语句用于从 switch 表达式中产生值。这些更改将简化日常编码,并为在 switch 中使用模式匹配铺平道路。这是 JDK 12 和 JDK 13 中的一个预览语言特性。
扩展switch,使其既可以用作语句,也可以用作语句,并且这两种形式都可以使用传统的case ...:
标签,或新的case ...->
标签。并添加了一个新的语句用于从switch表达式中生成值。这些更改将简化日常编码,并为在switch中使用模式匹配做好准备。这是JDK 12和JDK 13中的一个预览语言特性。
二、历史
JEP 325在2017年12月提出了switch表达式。JEP 325在2018年8月作为JDK 12的预览功能。其中的一个特性是重载break语句以从switch表达式获取返回值。但是在JDK 12的反馈表明这种break的使用是令人困惑的。所以,作为对JEP 325反馈的回应,JEP 354作为JEP 325的演变被创建。
JEP 354提出了一种新的语句yield
,并且恢复了break
原本的含义。JEP 354在2019年6月作为JDK 13的预览功能。对JDK 13的反馈表明,switch已经不用再进行任何更改,可以作为JDK 14中的最终和永久版本的表达式。
三、动机
当JDK的开发人员准备增强Java编程语言以支持模式匹配(JEP 305: Pattern Matching for instanceof (Preview) (openjdk.org))时,现有的switch语句的一些长期困扰用户的的不规则性成为了阻碍。其中包括开关标签之间的默认控制流行为(case语句贯穿)、default
块,以及switch仅仅作为一个语句的事实。
虽然这种传统的控制流通常适用于便捷低级代码,但是由于switch在高层级上下文中的使用,其容易出错的特性开始超过其灵活性。
例如,在下面的代码中,许多语句使其变得冗长,而这种视觉上的繁杂经常会掩盖难以调试的错误,其中丢失的语句意味着错误的发生。
1 | switch (day) { |
引入了一种新形式的标签,如果标签匹配,则仅执行标签右侧的代码。上面的代码可以改成这样:
1 | switch (day) { |
->
标签右侧的代码被限制为表达式、块或语句。这有一个令人愉悦的效果:如果一个分支的代码块中声明了一个局部变量,它只能在当前分支块中被使用,不能在其他分支中使用。这消除了传统switch的另一个烦恼,即局部变量的范围是整个开关块。示例如下:
1 | switch (day) { |
1 | switch (day) { |
许多现有的语句,其中每个分支要么分配给一个共同的目标变量,要么返回一个值,就像下面这样:
1 | int numLetters; |
上面的代码可以这样代替:
1 | int numLetters = switch (day) { |
四、详情
1、箭头标签
1 | switch (day) { |
2、Switch 表达式
1 | int numLetters = switch (day) { |
3、yield
关键字
大多数开关表达式都会在->
右侧有一个表达式。因为有时候需要一个完整的块,所以引入了一个新的yield
语句来产生一个值。
1 | int j = switch (day) { |
像switch语句一样,switch表达式也可以使用带有case标签的传统switch块。
1 | int result = switch (string) { |
break和yield这两个语句有助于轻松消除switch语句和switch表达式之间的歧义。
yield不是一个关键字,而是一个受限制的标识符(比如var),这意味着命名为yield的类是不合法的。
4、扩展
在switch表达式(2、Switch 表达式)中,所涉及到的分支场景必须要是全面的,即所有的情况必须要涉及一个case标签。然而switch语句不需要覆盖所有的情况。
这意味着,一个default
语句块是必须的。在一个覆盖所有情况的枚举switch表达式中,编译器会插入一个默认子句,用来指示枚举定义在编译时和运行时之间发生了更改。隐含地插入默认子句,使得代码更加健壮。当编译器编译代码时,编译期会检查是否显示处理了所有情况,如果开发人员插入了一个显示的默认子句,这可能会隐含一个错误。
此外,控制语句break
, yield
, return
, continue
不能跳过开关表达式,如下:
1 | for (int i = 0; i < 10; i++) { |
相关链接
JEP 361: Switch Expressions (openjdk.org)
JEP 305: Pattern Matching for instanceof (Preview) (openjdk.org)
OB links
OB tags
#JDK新特性