14

我去,你写的 switch 语句也太老土了吧

 4 years ago
source link: http://www.itwanger.com/life/2020/03/01/java-switch.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

I7RBBbF.png!web

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

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 语句的老土问题了。

IbYf22m.png!web

看到上图了吧,当不小心删掉 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。

b6Bjqe6.png!web

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

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

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

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

yuYn2eB.png!web

意思就是 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 啊!

JfUriaI.png!web

不服气?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 语句。这下清楚了吧?

yuiuYzV.gif

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

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

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

bAbymi2.png!web

(转载本站文章请注明作者和出处沉默王二)


Recommend

  • 52
    • video.weibo.com 6 years ago
    • Cache

    哈哈这也太敬业了吧!! ​

    哈哈这也太敬业了吧!! ​

  • 74
    • Engadget 中国版 cn.engadget.com 6 years ago
    • Cache

    Vivo 的 X21 也太像 iPhone X 了吧...

    同是步步高「兄弟」但在市场里斗得还挺凶的 Oppo、Vivo,这次居然把中端产品线的重要更新都放在了同一天进行。继白天 Oppo R15 系列在北京亮相之后,晚上 Vivo 也遥相呼应,在乌镇的舞台上端出了全新的 X21。就外观来说,这可能是 Vivo 手机史上跟苹果产品最相像的...

  • 50
    • www.v2ex.com 5 years ago
    • Cache

    Palm Phone 也太可爱了吧

    分享发现 - @20015jjw - Android 8.1,3.3 寸,非常小 /轻。性能对于这个屏幕大小足够,435 + 3G 内存。目前只有 Verizon 用户才能买,一个月$10 的 plan,可以和原号共享,机

  • 56
    • video.weibo.com 5 years ago
    • Cache

    这群小可爱也太萌了吧

    这群小可爱也太萌了吧

  • 35
    • dig.chouti.com 5 years ago
    • Cache

    女交警也太酷了吧!

    女交警也太酷了吧! - 抽屉新热榜-聚合每日热门、搞笑、有趣资讯女交警也太酷了吧!

  • 39
    • www.v2ex.com 4 years ago
    • Cache

    iOS13.1.2 也太垃圾了吧!

    问与答 - @douglas1997 - 更新了之后,卡死,关不了机。现在在等电池耗尽看能不能开机,真的真的很垃圾啊。好气啊,都什么垃圾玩意,真耽误事。

  • 24

    摘要: 抖音等短视频软件的兴起,让一些不为大众所知的歌曲一夜爆红,当我们遇到中意的音乐却苦恼于找不到资源时,“听歌识曲”的功能顺势而生。而这类技术是如何实现歌曲的精准识别的呢?跟我一起来通过华为云微认证DIY...

  • 13
    • database.51cto.com 3 years ago
    • Cache

    图解 SQL,这也太形象了吧!

    本文介绍关系数据库的设计思想:在 SQL 中,一切皆关系。

  • 12

    深圳 - @warren9527 - ![]( http://chuantu.xyz/t6/741/1607307556x-1566661166.jpg)![]( http://chuantu.xyz/t6/741/1607307

  • 4

    豆沙包这么老土的东西外国人反而喜欢吃 - 虎扑社区豆沙包这么老土的东西外国人反而喜欢吃烧杯基地...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK