深入剖析 Java 新特性
范学雷
前 Oracle 首席软件工程师,Java SE 安全组成员,OpenJDK 评审成员
16539 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 23 讲
深入剖析 Java 新特性
15
15
1.0x
00:00/00:00
登录|注册

06 | switch表达式:怎么简化多情景操作?

你好,我是范学雷。今天,我们聊一聊 Switch 表达式。
switch 表达式这个特性,首先在 JDK 12 中以预览版的形式发布。在 JDK 13 中,改进的 switch 表达式再次以预览版的形式发布。最后,switch 表达式在 JDK 14 正式发布。
不论你学习什么样的编程语言,合理地分析、判断、处理不同的情况都是必备的基本功。比如我们使用的 if-else 语句,还有 switch 语句,都是用来处理种种不同的情况的。 我们都知道 switch 语句,那么 switch 表达式又是什么呢?switch 语句和 switch 表达式又有什么不同呢?
如果你了解了 Java 的语句和表达式这两个基本概念,你的困扰也许会少一点。Java 规范里,表达式完成对数据的操作。一个表达式的结果可以是一个数值(i * 4);或者是一个变量(i = 4);或者什么都不是(void 类型)。
Java 语句是 Java 最基本的可执行单位,它本身不是一个数值,也不是一个变量。Java 语句的标志性符号是分号(代码)和双引号(代码块),比如 if-else 语句,赋值语句等。这样再来看,就很简单了:switch 表达式就是一个表达式,而 switch 语句就是一个语句。
switch 表达式是什么样子的?为什么需要 switch 表达式?我们还是通过案例和代码,一点一点地来学习 switch 表达式吧。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java 14引入了switch表达式这一新特性,它在处理多情景操作时能够简化代码逻辑和提高效率。相比传统的switch语句,switch表达式更加灵活,能够作为一个表达式返回值,而不仅仅是一个语句。文章通过一个计算月份天数的案例展示了传统switch语句的使用,指出了在使用过程中容易出现的错误和不便之处。为了解决这些问题,Java引入了switch表达式,使得多情景处理的代码块能够变成一个表达式,从而简化了代码逻辑和提高了可读性。通过引入switch表达式,Java语言在处理多情景操作时变得更加灵活和高效。在新的switch表达式中,出现了箭头标识符和yield关键字,使得多情景的合并更加简洁,消除了传统switch语句中容易出现的错误和冗余代码。此外,改进的switch语句也可以使用箭头标识符,不再需要显式的break语句来实现情景间的代码共享,从而提高了代码的可维护性和可读性。总的来说,Java 14中引入的switch表达式为多情景操作提供了更加灵活和高效的解决方案,极大地简化了代码逻辑,提高了代码的可读性和可维护性。文章还提出了对新特性的思考题,引发读者对于代码设计的深入思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入剖析 Java 新特性》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(12)

  • 最新
  • 精选
  • fatme
    终于明白思考题的思路,原来是要在编译期暴露出问题。这种思路,即使是对 jdk 8 以下也是有用的,只不过是不像 switch 表达式一样有语言本身的帮助。又学了一招,谢谢老师!

    作者回复: 不谢。

    2021-12-02
    2
  • ABC
    第一个问题是: 我们现在的代码能够检测到这个变化吗?如果不能,是不是只有系统崩溃的时候,我们才能够意识到问题的存在? 答: 如果是新增的月份现在的设计只能抛出异常,提醒我们修改代码.如果是减少了月份,在未更新JDK的情况下,代码正常运行.另外: JDK并非强更新,有些用户并不会频繁更新JDK,在我接触的一些项目,甚至还在使用JDK1.6,因此对于新特性和漏洞的修复,反应很迟缓. 第二个问题是,有没有更健壮的设计,能够帮助我们在系统崩溃之前就能够检测到这个意想不到的变化?从而给我们留出时间更改我们的代码和系统? 答: 持续关注JDK漏洞修复和版本发布,及时升级.这样所遇到的错误会第一时间反馈给我们,以留给我们修复问题的时间. 题外话,本来准备用java.time.LocalDate重写一下获取月份天数,想提交一个pr.发现用LocalDate来写,就三行代码.提pr有点太寒酸了,就发在这把(笑~) import java.time.LocalDate; var localDate=LocalDate.now(); // 判断是否为闰年. var isleapYear=localDate.isLeapYear(); System.out.println(localDate.getMonth().length(isleapYear)); 下面这段代码来自java.time.Month.class,这样判断感觉: public int length(boolean leapYear) { switch (this) { case FEBRUARY: return (leapYear ? 29 : 28); case APRIL: case JUNE: case SEPTEMBER: case NOVEMBER: return 30; default: return 31; } } 可以改写为: public int length(boolean leapYear) { return switch (this) { case FEBRUARY -> (leapYear ? 29 : 28); case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30; default -> 31; }; }

    作者回复: “就三行代码,提pr有点太寒酸了”,多小的改动都不会显得寒酸。任何一个开源社区,都需要很多小的改动。

    2021-11-26
    5
    2
  • aoe
    ->好用很多,switch 变好看了

    作者回复: 好看就是生产力!

    2021-11-26
    2
  • 猿人谷
    这个新特性看着很不错!

    作者回复: 它应该是我们以后使用switch的标准。

    2021-11-26
    2
  • xiaobang
    第二个问题,感觉可以用枚举类型来表示月份,这样switch表达式检查到没有穷举到全部值

    作者回复: 是的,如果月份的API重新设计的话,一定是使用枚举而不是整数来表达。

    2021-11-27
    1
  • 自然
    这里的 yield ,仅是 类似return的功能么?还是有多线程里的 yield 含义和用处?

    作者回复: 可以使用return的类比来理解。只是,返回的是表达式的值,而不是退出一个方法。

    2022-05-10
  • 第二少
    关于本讲思考题,如果要在编译期间检测出Calendar类增加了第十三个月,关键就是要有一种机制能穷举Calendar类里面定义的所有月份,比如可以用枚举来实现预定义的月份,就可以穷举了;然后对于 switch(x),只要 x 对应的值是可穷举的,那么jdk 17的编译器已经支持检查 x 对应的值在case里有没有全部被覆盖了,如果没有全部覆盖,就会报编译错误: java: switch 表达式不包含所有可能的输入值 如果是在ide里,不需要手动执行编译,就会有错误提示;如果编译器本身不支持做这种检查,那也可以充分利用ide来检查错误,比如IntellJ IDEA,可以自定义对应的inspections来做到这一点

    作者回复: idea是个很好的工具。

    2021-12-25
  • aoe
    今天《极客时间》两个专栏同时更新,主题都是 switch - 《深入剖析 Java 新特性》06 | Switch表达式:怎么简化多情景操作? - 《Tony Bai · Go 语言第一课》20|控制结构:Go中的switch语句有哪些变化? 对比结果 - Java17 居然可以比 Go 简洁! - 但然综合能力 Go 的更灵活 Java17 switch ```java String checkWorkday(int day) { return switch (day) { case 1, 2, 3, 4, 5 -> "it is a work day"; case 6, 7 -> "it is a weekend day"; default -> "are you live on earth"; }; } ``` Go switch ```go func checkWorkday(day int) string { switch day { case 1, 2, 3, 4, 5: return "it is a work day" case 6, 7: return "it is a weekend day" default: return "are you live on earth" } } ```

    作者回复: “综合能力 Go 的更灵活”,该怎么理解?从你给出的例子没有看出来。

    2021-11-26
    7
  • Jxin
    1.既然知道是一个弊大于利的方案,为何 switch表达式 还要使用 冒号标识符 来保留fall-through的模式? switch表达式 区别于 switch语句,可没有兼容问题。 2.猜测使用 -> 而不是 : 。应该是为了区别 switch语句 : 的语义,同时对称 Lambda 风格的表达方式。 3. switch语句 本身好像直接被归为坏味道,不建议使用(eff里看到的还是哪,忘了)。建议直接用 if卫语句/map策略模式 来替换。 switch表达式 从使用上来看,个人觉得语义上比 if卫语句/map策略模式都要清晰,使用这个写法可以提高阅读效率。唯一可惜的是case后面无法支持表达式,所以实际使用场景就会很受限(这个适用范围也跟编码设计能力有关,要用还是可以用的,只是没有支持表达式来的简单易用)。 课后题: 1.不能,第十三个月会获取不到天数,这好像不算是系统崩溃,只能说出bug才知道。 2.在 DaysInMonth 追加一个 一个 static 代码块(方法有很多),校验日期枚举实例是否超过12,超过告警。 这样至少在项目启动能感知到。

    作者回复: 1. 如果反对的声音再多一点, 这个冒号的表达式形式可能就没了。 2. 需要和冒号的形式区别开来。 3. 能够支持有限的表达式啊。 再看看下一讲吧, 里边有相关的话题。

    2021-11-26
  • 大胖子呀、
    第一个问题,目前的程序可以检测到多了一个月份,会通过最后的default语句抛出异常,但是检测不到少了一个月份; 第二个问题,我想着是否可以在default表达式里,通过遍历Calendar枚举的元素,去匹配出Calendar.AFTERDEC,但是我有疑问的是:月份多出了一个月,它的出现是否会导致已有月份的计算方式的改变?它的计算方式是按照31、30天,还是按照2月份,又或者是一个崭新的计算方式?这一块我确实不知道该如何在代码中实现,求老师指点。

    作者回复: 1. 多一个月检测到的方式是运行时抛出异常,这需要测试代码的配合,不能等到实际运行阶段。少一个月份,通常这个月份,比如FEBRUARY,就会从API里删除掉,这样编译时就可以检测出来了。 2. 你的疑问可以通过自己进一步的假设解决,你可以使用30/31/28,或者另外的一个你喜欢的数。

    2021-11-26
收起评论
显示
设置
留言
12
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部