尝鲜Java 12新特性:switch表达式

Java 12将在两个月后(2019/3/19)发布,现已进入RDP1阶段,确定加入8个JEP。其中对Java语法的改进是JEP 325: switch表达式。于是我迫不及待,提前感受一下更先进的语言特性。

因为12没有正式发布,本文使用自己编译的OpenJDK。嫌麻烦的话,也可以直接使用官方的ea版本。JEP325是预览(preview)特性,编译运行时需要添加--enable-preview参数。

顾名思义,这个feature是对switch动手脚的。包括两个方面。

1. 简化fall-through规则

下面这样的switch代码我们写过几万遍了

switch (today) {
    case SATURDAY:
    case SUNDAY:
        System.out.println("I‘m happy!");
        break;
    case MONDAY:
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
        System.out.println("I‘m sad...");
        break;
    default:
        System.out.println("I‘m confused.");
}

这段代码存在的问题是:

1. 内容不符合爱岗敬业的核心价值观(敲黑板!重要!!)
2. 多个条件对应相同代码时(比如MONDAY到FRIDAY),要重复写多个case,冗余且丑陋
3. 每一段代码后面都要有break,一旦忘记就会有编译器检测不到的逻辑错误
4. 变量作用域混乱

第四个问题可能长被忽略。case或者default后面是一连串的语句,而不是代码块(注意,它是没有大括号的)。这种情况下定义的局部变量,其作用域不是case后的部分,而是整个switch结构。因此,下面的代码无法通过编译。

switch (today) {
    case MODAY:
        int x = 1;
        break;
    default:
        int x = 0; //Variable x is already defined in the scope
}

编译器看到的是在一个作用域中存在两个x,非常违背人类的直觉。

上面的四个问题,除了1,剩下的万恶之源就是fall-through规则。即switch结构在找到第一个匹配的case条件后,会顺序执行后面所有case对应的代码,无论是否判断为真。这是40多年前C语言创造后来Java原样照抄的经典语法,但在今天看起来就显得很呆萌了,新的语言也几乎都放弃了fall-through。

好在,尽管后知后觉,从12开始Java开发者也可以选择更简洁清晰的语法了。就像这样

switch (today) {
    case SUNDAY, SATURDAY -> System.out.println("I‘m happy!");
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("I‘m happy, too!!");
    default -> System.out.println("I‘m confused.");
}

很容易看出语法的变化,这些变化也解决了上面的四个问题。归纳一下:

1. 程序内容积极向上,体现了新时代的奋斗精神(敲黑板!重要!!)
2. 对应相同动作的多个case合并为一行,代码更简洁
3. 条件和动作之间用->连接,这时fall-through规则失效。匹配到的分支代码执行完后直接跳出,不会继续执行下面的case对应的代码。也就是不需要再为每一个分支写break了。程序更简洁清晰,也更符合人类的直觉。
   需要注意,为了保持向后兼容性,case条件后依然可以使用:,这时fall-through还是有效的,即不能省略原有的break。而一个switch结构里不能混用->:,否则会有编译错误。
4. 每一个->后面只允许接一个表达式、一个代码块、或者一个throw语句。这样在代码块中定义的局部变量,其作用域就限制在代码块中,而不是蔓延到整个switch结构。逻辑更加清楚了。

2. switch作为表达式(expression)

switch结构一直是一个statement,而从Java 12开始,它也可以用作expression。从学院派的定义理解statement和expression的区别叫人头疼,如果说人话的话,就是switch可以有返回值了。

作为statement的switch没有返回值,所以我们不能写出这样的代码

x = switch (y) { ... }

如果需要根据不同的条件给某个变量赋值,我们以前只能这样做

String word = "";
switch (num) {
    case 1:
        word = "One";
        break;
    case 2:
        word = "Two";
        break;
    default:
        String result = String.format("Other (%d)", num);
        word = result;
}

让人难受的地方有两个。

1. 重复多次地写赋值语句,繁琐且易错。
2. 这段程序的终极目标是为word变量赋值,而赋值前必须在其他的地方初始化word,淡化了二者的逻辑关系,代码也显得琐碎。

从12开始我们可以这样改造代码

String word = switch (num) {
    case 1 -> "One";
    case 2 -> "Two";
    default -> {
        String result = String.format("Other (%d)", num);
        break result;
    }
};

可见,switch成了一个表达式(expression),它有自己的返回值。每一个分支只需要决定具体的返回值是什么,不需要考虑如何使用这个值。而全程只需要一次赋值操作。代码整体变得更简洁、紧凑、清晰。

而返回值又有两种写法。还记得吗,上一节提到过,->后只能接三样东西:表达式、代码块、throw语句。throw的情况没有返回值,先不管它。另外两种情况:

1. 如果分支只有一个表达式,那么表达式本身就是switch的值,比如上面例子里的"One""Two"
2. 如果分支是一个代码块,比如例子中的default,可以看到Java 12改造了break关键字,可以通过break result的形式返回值。switch并没有抛弃break,而是赋予它更重要的职能。

作为expression的switch也可以使用:,在这种情况下,各个分支必须用break关键字返回值。像这样

String word = switch (num) {
    case 1 : break "One";
    case 2 : break "Two";
    default : {
        String result = String.format("Other (%d)", num);
        break result;
    }
};

上面例子中,case 1case 2中的break不能省略,否则会有编译错误。

很显然,当switch用作expression时,每一个分支都必须有返回值(或者有throw异常)。我们不能写下面这样的代码

String word = switch (num) {
    case 1 -> "One";
    case 2 -> "Two";
    default -> {
        System.out.println("莫挨老子");
        //错误: switch rule completes without providing a value
    }
};

编译器不知道当num=3的时候应该返回什么,于是它愤怒地抛出了一个错误。

最后要强调,switch在不返回值的时候,还是一个statement。而作为expression并且在一句代码的结尾处时,不要忘了后面的分号!(亲自踩坑,友情提醒)

To be continue...

可能你会觉得这些改进还是小修小改,不值得过分激动。但是,JEP 325是JEP 305: Pattern Matching的依赖。虽然没有最终确定,但或许Pattern Matching会在不久后的几个版本正式引入,到时又将是语言层面的大革命。后续的几个版本还是值得期待的。

原文地址:https://www.cnblogs.com/tjxing/p/10306772.html

时间: 2024-10-10 07:23:46

尝鲜Java 12新特性:switch表达式的相关文章

Java 8 新特性 - Lambda表达式(一)

链接 Java8新特性——Lambda表达式(一) 原文地址:https://www.cnblogs.com/tonyq/p/8206131.html

Java12新特性 -- switch表达式

传统switch表达式的弊端: 匹配是自上而下的,如果忘记写break, 后面的case语句不论匹配与否都会执行: 所有的case语句共用一个块范围,在不同的case语句定义的变量名不能重复: 不能在一个case里写多个执行结果一致的条件: 整个switch不能作为表达式返回值: java 12 switch新特性: 使用 Java 12 中 Switch 表达式的写法,省去了 break 语句,避免了因少写 break 而出错. 同时将多个 case 合并到一行,显得简洁.清晰也更加优雅的表达

Java 8新特性:学习如何使用Lambda表达式,一看必懂

我将分为两篇系列文章来描述了使用Java 8的新特性 - lambda表达式. 目录 介绍 我们为什么需要lambdas? Lambdas的语法 功能接口 方法参考 构造函数参考 可变范围 默认方法 结论 介绍 Java 8版本是当前java界流行最广的一个版本.它的主要改进是在面向对象的基础上增加了对函数式编程的支持.在本文中,我将展示lambda的基本语法,并阐释几种适用的上下文环境. 我们为什么需要lambdas? lambda表达式是一个可以传递的代码块,允许您稍后执行它,只执行一次或多

Java 8新特性之旅:使用Stream API处理集合

在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda表达式增强方法”中,我已经深入解释并演示了通过lambda表达式和方法引用来遍历集合,使用predicate接口来过滤集合,实现接口的默认方法,最后还演示了接口静态方法的实现. 源代码都在我的Github上:可以从 这里克隆. 内容列表 使用流来遍历集合. 从集合或数组创建流. 聚合流中的值. 1.

Java 8新特性前瞻

快端午小长假了,要上线的项目差不多完结了,终于有时间可以坐下来写篇博客了. 这是篇对我看到的java 8新特性的一些总结,也是自己学习过程的总结. 几乎可以说java 8是目前为止,自2004年java 5发布以来的java世界中最大的事件了.它带来了java语言层面上的诸多改变,主要包括下面一些方面:语法.编译器.库.工具和运行时. 一,语法层面: 1,Lambda表达式. lambda表达式是一种可调用对象,它允许我们将函数作为函数参数传入.诸如C++.Groovy.Scala都已经支持la

Java 8新特性探究(八)精简的JRE详解

http://www.importnew.com/14926.html 首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 Java小组 工具资源 - 导航条 - 首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 Java小组 工具资源 Java 8新特性探究(八)精简的JRE详解 2015/02/05 | 分类: 基础技术 | 0 条评论 | 标签: JRE 分享到:2 原文出处: 成熟的毛毛虫的博客 Oracle公司如期发布了Java 8正式版!没有让广大javaer失望.对于

JDK7的新特性——switch语句可以用字符串语句

1 //jdk7.0中switch可以使用字符串做条件 2 public class TestSwitch02 { 3 public static void main(String[] args){ 4 String a = "向良峰"; 5 6 switch(a){//JDK 7的新特性,表达式可以是字符串! 7 case "哔哩哔哩": 8 System.out.println("输入的是哔哩哔哩"); 9 break; 10 case &q

【整理】Java 8新特性总结

闲语: 相比于今年三月份才发布的Java 10 ,发布已久的Java 8 已经算是老版本了(传闻Java 11将于9月25日发布....).然而很多报道表明:Java 9 和JJava10不是 LTS 版本,和过去的 Java 大版本升级不同,它们只有半年左右的开发和维护期.而未来的 Java11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本(得到 Oracle 等商业公司的长期支持服务).所以Java 8 就成了最新的一次LTS版本升级,这也是为什么Java开发者对J

Java 11 新特性介绍

Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个大版本,每个季度发布一个中间特性版本,并且做出不会跳票的承诺.通过这样的方式,Java 开发团队能够将一些重要特性尽早的合并到 Java Release 版本中,以便快速得到开发者的反馈,避免出现类似 Java 9 发布时的两次延期的情况. 按照官方介绍,新的版本发布周期将会严格按照时间节点,于每年