当前位置 博文首页 > CSDN资讯:技术大佬:我去,你写的 switch 语句也太老土了吧!

    CSDN资讯:技术大佬:我去,你写的 switch 语句也太老土了吧!

    作者:[db:作者] 时间:2021-06-17 15:46

    作者 |?沉默王二

    来源 | CSDN 博客专家

    出品?| CSDN(ID:CSDNnews)

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

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

     1private?static?String?createPlayer(PlayerTypes?playerType)?{
     2????switch?(playerType)?{
     3????????case?TENNIS:
     4????????????return?"网球运动员费德勒";
     5????????case?FOOTBALL:
     6????????????return?"足球运动员C罗";
     7????????case?BASKETBALL:
     8????????????return?"篮球运动员詹姆斯";
     9????????case?UNKNOWN:
    10????????????throw?new?IllegalArgumentException("未知");
    11????????default:
    12????????????throw?new?IllegalArgumentException(
    13????????????????????"运动员类型:?"?+?playerType);
    14
    15????}
    16}
    

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

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

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

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

     1private?static?String?createPlayer(PlayerTypes?playerType)?{
     2????String?player?=?null;
     3????switch?(playerType)?{
     4????????case?TENNIS:
     5????????????player?=?"网球运动员费德勒";
     6????????????break;
     7????????case?FOOTBALL:
     8????????????player?=?"足球运动员C罗";
     9????????????break;
    10????????case?BASKETBALL:
    11????????????player?=?"篮球运动员詹姆斯";
    12????????????break;
    13????????case?UNKNOWN:
    14????????????throw?new?IllegalArgumentException("未知");
    15????}
    16
    17????return?player;
    18}
    

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

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

     1private?static?String?createPlayer(PlayerTypes?playerType)?{
     2
     3???return?switch?(playerType)?{
     4
     5????????case?TENNIS?->?"网球运动员费德勒";
     6
     7????????case?FOOTBALL?->?"足球运动员C罗";
     8
     9????????case?BASKETBALL?->?"篮球运动员詹姆斯";
    10
    11????????case?UNKNOWN?->??throw?new?IllegalArgumentException("未知");
    12
    13????};
    14
    15}
    

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

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

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

     1public?enum?PlayerTypes?{
     2
     3????TENNIS,
     4
     5????FOOTBALL,
     6
     7????BASKETBALL,
     8
     9????PINGPANG,
    10
    11????UNKNOWN
    12
    13}
    

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

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

     1public?class?OldSwitchDemo?{
     2
     3????public?enum?PlayerTypes?{
     4
     5????????TENNIS,
     6
     7????????FOOTBALL,
     8
     9????????BASKETBALL,
    10
    11????????PINGPANG,
    12
    13????????UNKNOWN
    14
    15????}
    16
    17
    18
    19????public?static?void?main(String[]?args)?{
    20
    21????????System.out.println(createPlayer(PlayerTypes.BASKETBALL));
    22
    23????}
    24
    25
    26
    27????private?static?String?createPlayer(PlayerTypes?playerType)?{
    28
    29????????return?switch?(playerType)?{
    30
    31????????????case?TENNIS?->?"网球运动员费德勒";
    32
    33????????????case?FOOTBALL?->?"足球运动员C罗";
    34
    35????????????case?BASKETBALL?->?"篮球运动员詹姆斯";
    36
    37????????????case?PINGPANG?->?"乒乓球运动员马龙";
    38
    39????????????case?UNKNOWN?->?throw?new?IllegalArgumentException("未知");
    40
    41????????};
    42
    43????}
    44
    45}
    

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

     1private?static?String?createPlayer(PlayerTypes?playerType)?{
     2
     3????return?switch?(playerType)?{
     4
     5????????case?TENNIS?->?"网球运动员费德勒";
     6
     7????????case?FOOTBALL?->?"足球运动员C罗";
     8
     9????????case?BASKETBALL,PINGPANG?->?"牛逼运动员沉默王二";
    10
    11????????case?UNKNOWN?->?throw?new?IllegalArgumentException("未知");
    12
    13????};
    14
    15}
    

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

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

     1private?static?String?createPlayer(PlayerTypes?playerType)?{
     2
     3????return?switch?(playerType)?{
     4
     5????????case?TENNIS?->?{
     6
     7????????????System.out.println("网球");
     8
     9????????????yield?"网球运动员费德勒";
    10
    11????????}
    12
    13????????case?FOOTBALL?->?{
    14
    15????????????System.out.println("足球");
    16
    17????????????yield?"足球运动员C罗";
    18
    19????????}
    20
    21????????case?BASKETBALL?->?{
    22
    23????????????System.out.println("篮球");
    24
    25????????????yield?"篮球运动员詹姆斯";
    26
    27????????}
    28
    29????????case?PINGPANG?->?{
    30
    31????????????System.out.println("乒乓球");
    32
    33????????????yield?"乒乓球运动员马龙";
    34
    35????????}
    36
    37????????case?UNKNOWN?->?throw?new?IllegalArgumentException("未知");
    38
    39????};
    40
    41}
    

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

    先来看官方的解释:

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

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

     1private?static?String?createPlayer(NewSwitchDemo3.PlayerTypes?playerType)?{
     2
     3????String?var10000;
     4
     5????switch(playerType)?{
     6
     7????????case?TENNIS:
     8
     9????????????System.out.println("网球");
    10
    11????????????var10000?=?"网球运动员费德勒";
    12
    13????????????break;
    14
    15????????case?FOOTBALL:
    16
    17????????????System.out.println("足球");
    18
    19????????????var10000?=?"足球运动员C罗";
    20
    21????????????break;
    22
    23????????case?BASKETBALL:
    24
    25????????????System.out.println("篮球");
    26
    27????????????var10000?=?"篮球运动员詹姆斯";
    28
    29????????????break;
    30
    31????????case?PINGPANG:
    32
    33????????????System.out.println("乒乓球");
    34
    35????????????var10000?=?"乒乓球运动员马龙";
    36
    37????????????break;
    38
    39????????case?UNKNOWN:
    40
    41????????????throw?new?IllegalArgumentException("未知");
    42
    43????????default:
    44
    45????????????throw?new?IncompatibleClassChangeError();
    46
    47????}
    48
    49
    50
    51????return?var10000;
    52
    53}
    

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

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

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

    好了,我亲爱的读者朋友,以上就是本文的全部内容了,希望你学得开心。

    原文链接:

    https://blog.csdn.net/qing_gee/article/details/104586826

    推荐阅读?

    ?华为补助武汉员工,最高每日 2000 元;iPhone SE 2 量产或推迟;PowerShell 7.0 发布 | 极客头条

    ?腾讯云“抢救”微盟!开 766 次在线会议、调拨 100 多台服务器、闹钟只敢定 2 小时

    ?人工智能改变未来教育的5大方式!

    ?Linux 会成为主流桌面操作系统吗?

    ?6 个步骤,教你在Ubuntu虚拟机环境下,用Docker自带的DNS配置Hadoop | 附代码

    ?开发项目时如何选择区块链平台?我们分析了以太坊、Bitcoin via RSK、Ardor三个有趣的平台来给你回答!

    你点的每一个在看,我认真当成了喜欢

    上一篇:没有了
    下一篇:没有了