• 我去,你寫的 switch 語句也太老土了吧

    昨天早上通過遠程的方式 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 的代碼也不過是把部分秀技的工作交給了編譯器,還可能存在對舊版本不兼容、對隊友不友好的問題——代碼土點就土點唄,沒準是最實用的。

    “不好意思,我為昨天早上的囂張向你道歉。。。。。。”我向小王發送了一條信息。

    好了,我親愛的讀者朋友,以上就是本文的全部內容了,希望能夠博得你的歡心。對了,我還有一個小小的請求:原創不易,如果覺得有點用的話,請不要吝嗇你手中點贊的權力——因為這將是我寫作的最強動力。

    posted @ 2020-03-01 17:41  沉默王二  閱讀(...)  評論(...編輯  收藏
    贵州快三平台贵州快三主页贵州快三网站贵州快三官网贵州快三娱乐贵州快三开户贵州快三注册贵州快三是真的吗贵州快三登入贵州快三快三贵州快三时时彩贵州快三手机app下载贵州快三开奖 武山县 | 萨迦县 | 五寨县 | 太保市 | 双辽市 | 遂昌县 | 禹州市 | 大悟县 | 仪陇县 | 望谟县 | 温宿县 | 修文县 | 揭西县 | 陆河县 | 茂名市 | 资溪县 | 曲沃县 | 云龙县 | 宁乡县 | 阿荣旗 | 秦安县 | 巢湖市 | 澳门 | 望奎县 | 麦盖提县 | 临沭县 | 浪卡子县 | 太和县 | 新兴县 | 南木林县 | 屯留县 | 建湖县 | 会同县 | 金沙县 | 江城 | 漠河县 | 张家口市 | 新民市 | 满城县 | 山西省 | 玉树县 | 九龙县 | 浦城县 | 务川 | 衡东县 | 辉县市 | 北辰区 | 嵩明县 | 阿拉善左旗 | 新闻 | 南康市 | 永仁县 | 阳泉市 | 蒙城县 | 保靖县 | 噶尔县 | 兰坪 | 天气 | 廊坊市 | 绥滨县 | 呼玛县 | 和龙市 | 营口市 | 定襄县 | 阳原县 | 观塘区 | 禄丰县 | 江永县 | 长宁区 | 乌苏市 | 姚安县 | 芜湖市 | 城步 | 绩溪县 | 格尔木市 | 弋阳县 | 略阳县 | 仙游县 | 道孚县 | 东乌 | 大城县 | 顺昌县 | 鹿邑县 | 灵武市 | 彰化市 | 和平区 | 育儿 | 贺兰县 | 临潭县 | 和田市 | 哈密市 | 苍溪县 | 宜昌市 | 海宁市 | 玉龙 | 华容县 | 缙云县 | 外汇 | 山东省 | 临洮县 | 苍南县 | 昭通市 | 侯马市 | 龙川县 | 景谷 | 同江市 | 增城市 | 石渠县 | 孟连 | 保亭 | 敖汉旗 | 海安县 | 永嘉县 | 昌乐县 | 英山县 | 周宁县 | 浮梁县 | 安图县 | 卢龙县 | 兴海县 | 株洲县 | 宿松县 | 维西 | 荆门市 | 武川县 | 奉节县 | 肇源县 | 仁怀市 | 安泽县 | 鄂州市 | 绿春县 | 山阴县 | 淅川县 | 勐海县 | 九龙城区 | 五常市 | 定远县 | 浏阳市 | 宜州市 | 文山县 | 出国 | 浮山县 | 长治县 | 昔阳县 | 藁城市 | 红桥区 | 康马县 | 田东县 | 东山县 | 舒兰市 | 榆中县 | 毕节市 | 亳州市 | 久治县 | 政和县 | 镇安县 | 林州市 | 保山市 | 和顺县 | 胶南市 | 水城县 | 海淀区 | 普陀区 | 厦门市 | 新乡县 | 卫辉市 | 新民市 | 嘉禾县 | 岳阳市 | 江津市 | 浠水县 | 大庆市 | 通道 | 龙陵县 | 长垣县 | 榆树市 | 渭南市 | 鄢陵县 | 青龙 | 贵溪市 | 米脂县 | 邵武市 | 得荣县 | 阳城县 | 沂南县 | 中山市 | 铜川市 | 涿州市 | 九台市 | 凤城市 | 宁武县 | 齐齐哈尔市 | 治县。 | 柳州市 | 凌云县 | 威海市 | 洮南市 | 文水县 | 北川 | 清新县 | 佳木斯市 | 滦平县 | 会宁县 | 新蔡县 | 紫阳县 | 二连浩特市 | 甘洛县 |