• 我去,你寫的 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下载贵州快三开奖 铜鼓县 | 隆昌县 | 万年县 | 桦甸市 | 江达县 | 德阳市 | 天镇县 | 新安县 | 宜君县 | 望都县 | 民县 | 洞口县 | 墨脱县 | 石柱 | 南皮县 | 徐水县 | 永嘉县 | 闸北区 | 灵璧县 | 宿州市 | 启东市 | 嘉善县 | 积石山 | 平度市 | 呼玛县 | 吉木萨尔县 | 贺兰县 | 宁远县 | 林西县 | 龙山县 | 房产 | 江西省 | 台江县 | 突泉县 | 星子县 | 通江县 | 科尔 | 定兴县 | 龙江县 | 高青县 | 金溪县 | 金乡县 | 邻水 | 来凤县 | 石门县 | 吉安市 | 蚌埠市 | 正镶白旗 | 长岭县 | 象山县 | 九台市 | 读书 | 玉林市 | 勃利县 | 卓尼县 | 郴州市 | 平山县 | 西峡县 | 岫岩 | 扎兰屯市 | 化州市 | 固原市 | 土默特左旗 | 江安县 | 武山县 | 方山县 | 高淳县 | 顺昌县 | 高密市 | 小金县 | 防城港市 | 苍梧县 | 天峨县 | 长垣县 | 太仓市 | 罗城 | 龙州县 | 潜山县 | 五峰 | 大余县 | 邯郸县 | 安岳县 | 瑞安市 | 保山市 | 双鸭山市 | 绥德县 | 兰溪市 | 壤塘县 | 沿河 | 兴和县 | 万载县 | 古丈县 | 资阳市 | 盐源县 | 镇康县 | 巴塘县 | 洪雅县 | 治县。 | 谷城县 | 浦江县 | 林西县 | 刚察县 | 凯里市 | 鹿邑县 | 万荣县 | 大英县 | 赤峰市 | 巫山县 | 营口市 | 道孚县 | 盘锦市 | 远安县 | 志丹县 | 巴林右旗 | 天门市 | 万山特区 | 盐山县 | 进贤县 | 慈利县 | 崇左市 | 凤庆县 | 格尔木市 | 内丘县 | 固阳县 | 彩票 | 称多县 | 六枝特区 | 武功县 | 石棉县 | 瑞昌市 | 浙江省 | 泾源县 | 周口市 | 阜平县 | 云安县 | 宣武区 | 恩平市 | 尖扎县 | 宁波市 | 通山县 | 双柏县 | 霸州市 | 周宁县 | 随州市 | 南充市 | 湄潭县 | 吴堡县 | 民丰县 | 子长县 | 剑川县 | 湘潭县 | 栖霞市 | 封丘县 | 西乌珠穆沁旗 | 建平县 | 顺义区 | 安岳县 | 资溪县 | 和林格尔县 | 彭阳县 | 利津县 | 甘孜 | 海阳市 | 建水县 | 江山市 | 会理县 | 屏东市 | 无锡市 | 秭归县 | 武威市 | 太原市 | 大洼县 | 绍兴市 | 柘荣县 | 沁阳市 | 许昌市 | 遂平县 | 微山县 | 枞阳县 | 文安县 | 西盟 | 永平县 | 廉江市 | 抚松县 | 子洲县 | 宁乡县 | 承德市 | 阳朔县 | 晋中市 | 汝南县 | 彭阳县 | 台州市 | 茂名市 | 甘德县 | 侯马市 | 长丰县 | 原阳县 | 五指山市 | 托克托县 | 长岛县 | 德保县 | 甘洛县 | 年辖:市辖区 | 保定市 | 楚雄市 | 光山县 | 香河县 |