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

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

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

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);

    }
}
复制代码

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

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

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

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

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 语句在这种状况下是能够省略的。blog

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

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。get

而且,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 的代码也不过是把部分秀技的工做交给了编译器,还可能存在对旧版本不兼容、对队友不友好的问题——代码土点就土点呗,没准是最实用的。

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

好了,我亲爱的读者朋友,以上就是本文的所有内容了,但愿可以博得你的欢心。对了,我还有一个小小的请求:原创不易,若是以为有点用的话,请不要吝啬你手中点赞的权力——由于这将是我写做的最强动力。

相关文章
相关标签/搜索