昨天早上通过远程的方式 review 了两名新来同事的代码,大部分代码都写得很漂亮,严谨的同时注释也很到位,这令我非常满意。但当我看到他们当中有一个人写的 switch 语句时,还是忍不住破口大骂:“我擦,小王,你丫写的 switch 语句也太老土了吧!”


来看看小王写的代码吧,看完不要骂我装逼啊。

private static String createPlayer(PlayerTypes playerType) {
    switch (playerType) {
        case TENNIS:
            return "网球运动员费德勒";
        case FOOTBALL:
            return "足球运动员C罗";
        case BASKETBALL:
            return "篮球运动员詹姆斯";
        case UNKNOWN:
            throw new IllegalArgumentException("未知");
        default:
            throw new IllegalArgumentException(
                    "运动员类型: " + playerType);

    }
}

看完上述代码后,你是不是会发出这样的感慨——“代码写得很好,没有任何问题啊!”是不是觉得我在无事生非,错怪了小王!但此时我要送上《了不起的盖茨比》中的一句话:

我年纪还轻,阅历不深的时候,我父亲教导过我一句话,我至今还念念不忘。 “每逢你想要批评任何人的时候, ”他对我说,“你就记住,这个世界上所有的人,并不是个个都有过你拥有的那些优越条件。”

哈哈,这句话不光是让你看的,也是给我看的。是时候冷静下来谈谈上述 switch 语句的老土问题了。


看到上图了吧,当不小心删掉 default 语句后,编译器就会报错,提示:“没有返回语句”,为了解决这个问题,我们可以新建一个 player 变量作为返回结果,就像下面这样:

private static String createPlayer(PlayerTypes playerType) {
    String player = null;
    switch (playerType) {
        case TENNIS:
            player = "网球运动员费德勒";
            break;
        case FOOTBALL:
            player = "足球运动员C罗";
            break;
        case BASKETBALL:
            player = "篮球运动员詹姆斯";
            break;
        case UNKNOWN:
            throw new IllegalArgumentException("未知");
    }

    return player;
}

当添加了 player 变量后,case 语句中就需要添加上 break 关键字;另外在 switch 语句结束后,返回 player。这时候,编译器并不会提示任何错误,说明 default 语句在这种情况下是可以省略的。

从 JDK 12 开始(本例使用的是 JDK 13),switch 语句升级了,不仅可以像传统的 switch 语句那样作为条件的判断,还可以直接作为一个返回结果。来对小王的代码进行改造,如下所示:

private static String createPlayer(PlayerTypes playerType) {
   return switch (playerType) {
        case TENNIS -> "网球运动员费德勒";
        case FOOTBALL -> "足球运动员C罗";
        case BASKETBALL -> "篮球运动员詹姆斯";
        case UNKNOWN ->  throw new IllegalArgumentException("未知");
    };
}

够 fashion 吧?不仅 switch 关键字之前加了 return 关键字,case 中还见到了 Lambda 表达式的影子,中划线和箭头替代了冒号,意味着箭头右侧的代码只管执行无须 break。


并且,default 语句变成了可选项,可有可无,不信?你也动手试试。

新的 switch 语句足够的智能化,除了有上述的 3 个优势,还可以对枚举类型的条件进行校验。假如在 PlayerTypes 中增加了新的类型 PINGPANG(乒乓球):

public enum PlayerTypes {
    TENNIS,
    FOOTBALL,
    BASKETBALL,
    PINGPANG,
    UNKNOWN
}

此时编译器会发出以下警告:


意思就是 switch 中的 case 条件没有完全覆盖枚举中可能存在的值。好吧,那就把 PINGPANG 的条件加上吧。来看一下完整的代码:

public class OldSwitchDemo {
    public enum PlayerTypes {
        TENNIS,
        FOOTBALL,
        BASKETBALL,
        PINGPANG,
        UNKNOWN
    }

    public static void main(String[] args) {
        System.out.println(createPlayer(PlayerTypes.BASKETBALL));
    }

    private static String createPlayer(PlayerTypes playerType) {
        return switch (playerType) {
            case TENNIS -> "网球运动员费德勒";
            case FOOTBALL -> "足球运动员C罗";
            case BASKETBALL -> "篮球运动员詹姆斯";
            case PINGPANG -> "乒乓球运动员马龙";
            case UNKNOWN -> throw new IllegalArgumentException("未知");
        };
    }
}

switch 语句变成了强大的 switch 表达式,美滋滋啊!那假如一个运动员既会打篮球又会打乒乓球呢?

private static String createPlayer(PlayerTypes playerType) {
    return switch (playerType) {
        case TENNIS -> "网球运动员费德勒";
        case FOOTBALL -> "足球运动员C罗";
        case BASKETBALL,PINGPANG -> "牛逼运动员沉默王二";
        case UNKNOWN -> throw new IllegalArgumentException("未知");
    };
}

就像上述代码那样,使用英文逗号“,”把条件分割开就行了,666 啊!


不服气?switch 表达式还有更厉害的,-> 右侧还可以是 {} 括起来的代码块,就像 Lambda 表达式那样。

private static String createPlayer(PlayerTypes playerType) {
    return switch (playerType) {
        case TENNIS -> {
            System.out.println("网球");
            yield "网球运动员费德勒";
        }
        case FOOTBALL -> {
            System.out.println("足球");
            yield "足球运动员C罗";
        }
        case BASKETBALL -> {
            System.out.println("篮球");
            yield "篮球运动员詹姆斯";
        }
        case PINGPANG -> {
            System.out.println("乒乓球");
            yield "乒乓球运动员马龙";
        }
        case UNKNOWN -> throw new IllegalArgumentException("未知");
    };
}

细心的同学会发现一个之前素未谋面的关键字 yield,它和传统的 return、break 有什么区别呢?

先来看官方的解释:

A yield statement transfers control by causing an enclosing switch expression to produce a specified value.

意思就是说 yield 语句通过使一个封闭的 switch 表达式产生一个指定值来转移控制权。为了进一步地了解 yield 关键字,我们可以反编译一下字节码:

private static String createPlayer(NewSwitchDemo3.PlayerTypes playerType) {
    String var10000;
    switch(playerType) {
        case TENNIS:
            System.out.println("网球");
            var10000 = "网球运动员费德勒";
            break;
        case FOOTBALL:
            System.out.println("足球");
            var10000 = "足球运动员C罗";
            break;
        case BASKETBALL:
            System.out.println("篮球");
            var10000 = "篮球运动员詹姆斯";
            break;
        case PINGPANG:
            System.out.println("乒乓球");
            var10000 = "乒乓球运动员马龙";
            break;
        case UNKNOWN:
            throw new IllegalArgumentException("未知");
        default:
            throw new IncompatibleClassChangeError();
    }

    return var10000;
}

编译器在生成字节码的时候对 yield 关键字做了自动化转义,转成了传统的 break 语句。这下清楚了吧?


但是,话又说出来,那些看似 fashion 的代码也不过是把部分秀技的工作交给了编译器,还可能存在对旧版本不兼容、对队友不友好的问题——代码土点就土点呗,没准是最实用的。

“不好意思,我为昨天早上的嚣张向你道歉。。。。。。”我向小王发送了一条信息。

好了,我亲爱的读者朋友,以上就是本文的全部内容了,希望能够博得你的欢心。对了,我还有一个小小的请求:原创不易,如果觉得有点用的话,请不要吝啬你手中点赞的权力——因为这将是我写作的最强动力。


我去,你写的 switch 语句也太老土了吧的更多相关文章

  1. Switch选择语句能否作用在String【字符串】上,也就是能否这么写:Switch(一个字符串变量)?

    Switch选择语句能否作用在String[字符串]上,也就是能否这么写:Switch(一个字符串变量)? 解答:不可以,只能处理int,byte,short,char,(其实是只能处理int,其它三 ...

  2. 通过goto语句学习if...else、switch语句并简单优化

    goto语句在C语言中实现的就是无条件跳转,第二章一上来就介绍goto语句就是要通过goto语句来更加清楚直观的了解控制结构. 我理解的goto语句其实跟switch语句有相似之处,都是进行跳转.不同 ...

  3. switch语句下的变量声明和定义

    switch语句下的变量声明和定义的问题: switch...case...语句中存在声明和定义会出现一些问题.这个由switch语法特性决定的, switch中每个case都是平等的层次,区别于一般 ...

  4. 透过IL看C#:switch语句(转)

    透过IL看C# switch语句(上) 摘要: switch语句是 C#中常用的跳转语句,可以根据一个参数的不同取值执行不同的代码.本文介绍了当向 switch语句中传入不同类型的参数时,编译器为其生 ...

  5. PROCESS_YIELD()宏和C语言的switch语句< contiki学习笔记之七>

    写在前面:  按照main()函数的代码一行一行的分析,该是看到了 etimer_process 这个位置.但是etimer_process实现里的一个宏 PROCESS_YIELD()引出了很多故事 ...

  6. switch语句和switch-case与if-else之间的转换

    switch语句格式:switch(变量){case 常量1:语句1;break;case 常量2:语句2;break;......default:语句;break;}特点:1.根据变量的值,选择相应 ...

  7. C#学习笔记(四):switch语句

    条件语句 switch语句快速生成枚举方法,复制枚举名在switch()里,双击TAB 快速生成方法,用纠错功能 随机数 using System; using System.Collections. ...

  8. 重构--去除丑陋的switch语句

    最近几天,在进行重构的时候,遇到了一个极其丑陋的代码(自己写的 /捂脸  当时时间紧,于是....),今天去重构的时候无论如何也想不出方法,去除这个丑陋的switch语句 ,于是写篇博客,让自己记住这 ...

  9. Java中的switch语句——通过示例学习Java编程(8)

    作者:CHAITANYA SINGH 来源:https://www.koofun.com//pro/kfpostsdetail?kfpostsid=19 当我们在代码逻辑中有多个选项,而且需要为每个选 ...

随机推荐

  1. Debian8.8同步时间

    1.安装ntpdate 2.设置当前年月   如:sudo date -s 2017-05-18 3.同步:sudo ntpdate /usr/sbin/ntpdate time.nist.gov

  2. 爬虫笔记(十)——学会使用Fiddler

    Fiddler是一个常见的抓包分析软件,同时我们可以利用它详细地对HTTP请求进行分析,并模拟对应的HTTP请求. 为什么使用Fiddler软件? 网络爬虫是自动爬取网页的程序,在爬取的过程中必然涉及 ...

  3. MySQL允许某个IP网段从远程访问的方法

    grant select,insert,update,create on test.* to test@'192.168.8.%' identified by '123456';     允许增删改查 ...

  4. winform显示word和ppt文档

    最近所做的项目中需要在Winform窗体中显示Office文档.刚开始就使用webBrowser控件实现的,但是后来发现这个控件在显示Office文档的时候有个限制:只支持Office2003之前的版 ...

  5. conditon 实现等待/通知

    synchronized 与wait() 和notify() notifyAll() 方法相结合可以实现等待 通知 ReetrantLock也可以实现同样的功能 需要借助condition对象,一个l ...

  6. 关于mysql的符合主键的定义和解释

    DROP TABLE IF EXISTS `v9_vote_data`;CREATE TABLE `v9_vote_data` (  `userid` mediumint(8) unsigned DE ...

  7. 吴裕雄--天生自然 R语言开发学习:基础知识

    1.基础数据结构 1.1 向量 # 创建向量a a <- c(1,2,3) print(a) 1.2 矩阵 #创建矩阵 mymat <- matrix(c(1:10), nrow=2, n ...

  8. python学习笔记(0)python基础概念

    一.字符集 说字符集之前,先说下2进制的故事,计算机比较傻只认识2进制,什么是2进制,就是0,1,计算机只认识这俩数字,其他的都不认识,这样的0或1为一"位",规定8位为一个字节, ...

  9. 探索真实事物的虚拟再现——微软亚洲研究院SIGGRAPH Asia 2014精彩入选论文赏析

    Asia 2014精彩入选论文赏析" title="探索真实事物的虚拟再现--微软亚洲研究院SIGGRAPH Asia 2014精彩入选论文赏析"> SIGGRAP ...

  10. 虚拟网卡 TUN/TAP 驱动程序设计原理(经典)

    盗用-收藏 简介 虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装.本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱 ...