以下代码需要使用Java 13 才能运行,并且需要设置语言级别为13(Preview).IDEA中File-Project Structure-Project language level-选择 13(Preview)-Switch expressions,text blocks.
以下内容机翻整理自OpenJDK官方:JEP 354,稍有改动.
简述
在Java 13发布中,提供了两个预览功能:一个是文本块,另一个是Switch表达式改进.这篇是关于Switch表达式改进的介绍.文本块的文章地址是: Java 13预览:文本块
基本操作
在最开始我们是这样用Switch表达式的:
int day = SUNDAY; 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(8); break; case WEDNESDAY: System.out.println(9); break; }
通过break的”作用”,合并计算多个结果.看起来似乎没什么问题,但如果有个break写错了,也就意味着计算结果出现了偏差.
在Java 13提供的Switch表达式,是这样的:
switch (day) { case MONDAY, FRIDAY, SUNDAY -> { System.out.println(5); } case TUESDAY -> System.out.println(7); case THURSDAY, SATURDAY -> System.out.println(8); case WEDNESDAY -> System.out.println(9); }
通过一种优雅的方式,重写了上面的示例代码.最主要的好处是,去掉了break,减少错误的发生.
case MONDAY, FRIDAY, SUNDAY -> { System.out.println(5); }
这个地方是为了演示,在Switch的case中,也可以使用代码块.
使用Switch动态取值
有时候我们会这样写代码,反正我是这样写过…
通过Switch来动态获取值.
在以前我们是这样写的:
int numLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; default: throw new IllegalStateException("Wat: " + day); } System.out.println(numLetters);
通过break和case结合起来,对Switch外面的变量进行动态赋值,看起来略微复杂了一些.现在,Java 13又提供了一个简单的办法:
int day1 = MONDAY; String n1umLetters = switch (day1) { case MONDAY, FRIDAY, SUNDAY -> "6"; case TUESDAY -> "7"; case THURSDAY, SATURDAY -> "8"; case WEDNESDAY -> "9"; // 这样使用,必须添加default,否则会提示: Switch expression does not cover all possible input value(开关表达式未涵盖所有可能的输入值) // 意思就是,如果输入的值没有在case中,则无法找到返回值. default -> "default"; };
在这个地方用String是为了演示String在其中同样可用.
另外需要注意的一点是:
这样使用,必须添加default,否则会提示: Switch expression does not cover all possible input value(开关表达式未涵盖所有可能的输入值).意思就是,如果输入的值没有在case中,则无法找到返回值.
关于箭头标签
如果case匹配,则执行箭头右侧的表达式或语句,否则不执行任何操作
static void howMany(int k) { switch (k) { case 1 -> System.out.println("one"); case 2 -> System.out.println("two"); default -> System.out.println("many"); } }
看起来简洁明了.同时也可以在下面的示例中使用上面的方式定义代码:
static void howMany1(int k) { System.out.println( switch (k) { case 1 -> "one"; case 2 -> "two"; default -> "many"; } ); }
在代码块中使用yield
在Switch表达式返回的值中,有可能会使用到代码块.而这时,我们则可以用到yield语句.如下所示:
int j = switch (day) { case MONDAY -> 0; case TUESDAY -> 1; default -> { int k=day; int result=fyield(k); yield result; } }; static int fyield(int i) { return i * 2; }
这样就可以调用其它方法,来进行返回值的处理之后,再返回.
来自官方文档的可能遇到的错误提示
机翻.
Switch表达的情况必须详尽 ; 对于所有可能的值,必须有一个匹配的开关标签。(显然,Switch声明并非必须详尽。)
实际上,这通常意味着需要一个default子句。但是,enum Switch对于覆盖所有已知常量的表达式,default编译器会插入一个子句以指示该enum定义在编译时和运行时之间已更改。依靠这种隐式default子句的插入可以使代码更健壮。现在,当重新编译代码时,编译器将检查所有情况是否得到明确处理。如果开发人员插入了显式default子句(如今天的情况),则可能的错误将被隐藏。
此外,Switch表达式必须以一个值正常完成,或者必须通过引发异常来突然完成。这有许多后果。首先,编译器会检查每个开关标签是否匹配,然后产生一个值。
int i = switch (day) { case MONDAY -> { System.out.println("Monday"); // ERROR! Block doesn't contain a yield statement } default -> 1; }; i = switch (day) { case MONDAY, TUESDAY, WEDNESDAY: yield 0; default: System.out.println("Second half of the week"); // ERROR! Group doesn't contain a yield statement };
另一种后果是,控制语句,break,yield,return和continue,无法通过跳出Switch表达式,如在下文中:
for (int i = 0; i < MAX_VALUE; ++i) { int k = switch (e) { case 0: yield 1; case 1: yield 2; default: continue z; // ERROR! Illegal jump through a Switch expression }; ... }
示例源码
示例完整源码如下:
import static java.util.Calendar.*; public class Java13SwitchTestDemo { public static void main(String[] args) { // 简述 int day = SUNDAY; 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(8); break; case WEDNESDAY: System.out.println(9); break; } // Java 13 新的方式 switch (day) { case MONDAY, FRIDAY, SUNDAY -> { System.out.println(5); } case TUESDAY -> System.out.println(7); case THURSDAY, SATURDAY -> System.out.println(8); case WEDNESDAY -> System.out.println(9); } int numLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; default: throw new IllegalStateException("Wat: " + day); } System.out.println(numLetters); int day1 = MONDAY; String n1umLetters = switch (day1) { case MONDAY, FRIDAY, SUNDAY -> "6"; case TUESDAY -> "7"; case THURSDAY, SATURDAY -> "8"; case WEDNESDAY -> "9"; default -> "default"; }; howMany(1); howMany(2); howMany(3); System.out.println("------"); howMany1(8); howMany1(9); howMany1(10); System.out.println("------"); int j = switch (day) { case MONDAY -> 0; case TUESDAY -> 1; default -> { int k=day; int result=fyield(k); yield result; } }; System.out.println(j); } static int fyield(int i) { return i * 2; } /** * 箭头标签 * <p> * 如果case匹配,则执行箭头右侧的表达式或语句,否则不执行任何操作, * * @param k */ static void howMany(int k) { switch (k) { case 1 -> System.out.println("one"); case 2 -> System.out.println("two"); default -> System.out.println("many"); } } /** * 可以重写上面的方法为 * * @param k */ static void howMany1(int k) { System.out.println( switch (k) { case 1 -> "one"; case 2 -> "two"; default -> "many"; } ); } }