Kotlin 入門(mén)到進(jìn)階(4) -- 結(jié)構(gòu)化邏輯:順序、選擇瞻润、循環(huán)

一喘垂、條件判斷

1、when精講

在 Java 中有 switch 語(yǔ)句绍撞,在 Kotlin 中使用 when 來(lái)代替 switch正勒。同時(shí) when 也可以代替 if 。你以為 when 只是用來(lái)代替 switch 和 if 的嗎傻铣?其實(shí)遠(yuǎn)遠(yuǎn)不止這些章贞,其中還包含了一些不為認(rèn)知的小秘密。下面我們都會(huì)為大家一一揭曉非洲。

1.1鸭限、when的基本語(yǔ)法

when(parameter){
    branch1 -> logic
    branch2 -> logic
}

when 括號(hào)里是參數(shù),參數(shù)是可選的两踏。箭頭(->) 左邊是條件分支败京,右邊是對(duì)應(yīng)的邏輯體

when 不需要向 switch 那樣需要加上 break 語(yǔ)句,符合條件自動(dòng)具有 break 功能

如果邏輯體代碼比較多梦染,可以放到花括號(hào) {} 里:

when(parameter){
    branch1 -> {
        //...
    }
    branch1 -> {
        //...
    }
}

如果要組合多個(gè)分支赡麦,可以使用逗號(hào)(,)分隔分支:

when(parameter){
    branch1,branch1 -> {
        //...
    }
}

1.2、枚舉類(lèi)對(duì)象作為when參數(shù)

fun getMnemonic(color: Color) = when (color) {
     Color.RED -> "Richard" 
     Color.ORANGE -> "Of" 
     Color.YELLOW -> "York" 
     Color.GREEN -> "Gave" 
     Color.BLUE -> "Battle" 
     Color.INDIGO -> "In" 
     Color.VIOLET -> "Vain"
}

需要注意的是弓坞,when 使用枚舉對(duì)象作為參數(shù)隧甚,需要把該枚舉類(lèi)的所有對(duì)象列舉完

所以 枚舉對(duì)象作為 when 參數(shù)不需要 else 分支

1.3、任意對(duì)象作為when參數(shù)

Kotlin 中的 when 比 Java 中的 switch 功能更強(qiáng)大

Java 的 switch 參數(shù)只能是 枚舉常量渡冻、字符串戚扳、整型或整型的包裝類(lèi)型(浮點(diǎn)型不可以)

Kotlin 的 when 可以是任意對(duì)象:

fun mix(c1: Color, c2: Color) = when (setOf(c1, c2)) {
    
    setOf(RED, YELLOW) -> ORANGE 
    
    setOf(YELLOW, BLUE) -> GREEN 
    
    setOf(BLUE, VIOLET) -> INDIGO
    
    //需要處理 其他 情況
    else -> throw Exception("Dirty color") 
}

1.4、無(wú)參數(shù)的when表達(dá)式

上面的 mix 函數(shù)比較低效族吻,因?yàn)槊看伪容^的時(shí)候都會(huì)創(chuàng)建一個(gè)或多個(gè) set 集合

如果該函數(shù)調(diào)用頻繁帽借,會(huì)創(chuàng)建很多臨時(shí)對(duì)象

可以使用無(wú)參的 when 表達(dá)式來(lái)改造下:

fun mixOptimized(c1: Color, c2: Color) = when {
    (c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) ->
        ORANGE
    (c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) ->
        GREEN
    (c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) ->
        INDIGO
    else -> throw Exception("Dirty color")
}

無(wú)參數(shù)的 when 表達(dá)式的條件分支必須是 boolean 類(lèi)型

1.5珠增、智能類(lèi)型轉(zhuǎn)換(smart-casts)

在 Java 中對(duì)某個(gè)對(duì)象進(jìn)行類(lèi)型轉(zhuǎn)換的時(shí)候時(shí)候,需要通過(guò) instanceof 來(lái)判斷是否可以被強(qiáng)轉(zhuǎn)

void test(Object obj) {
    if (obj instanceof String) {
        String str = (String) obj;
        str.substring(0, str.length() / 2);
    }
    //...
}

Kotlin 通過(guò) is 關(guān)鍵字來(lái)判斷類(lèi)型砍艾,并且編譯器會(huì)自動(dòng)幫你做類(lèi)型轉(zhuǎn)換

fun test(obj: Any) {
    if (obj is String) {
        // 不需要手動(dòng)做類(lèi)型轉(zhuǎn)換操作
        obj.substring(0, obj.length / 2)
    }
    //...
}

1.6蒂教、when原理分析

例如下面的程序:

fun testWhen(index: Int) {
    when (index) {
        0 -> {
            println("0")
        }
        1, 2 -> {
            println("1,2")
        }
    }
}

也就是說(shuō),當(dāng) index = 1 或者 2 都會(huì)執(zhí)行 println("1,2")

我們對(duì)上面的例子進(jìn)行反編譯:

public final void testWhen(int index) {
   String var2;
   boolean var3;
   switch(index) {
   case 0:
      var2 = "0";
      var3 = false;
      System.out.println(var2);
      break;
   case 1:
   case 2:
      var2 = "1,2";
      var3 = false;
      System.out.println(var2);
   }
}

發(fā)現(xiàn)脆荷,它底層還是通過(guò) Java 的 switch 來(lái)實(shí)現(xiàn)的凝垛。我們對(duì)上面的 kotlin 案例進(jìn)行小的修改:

fun testWhen(index: Int) {
    when (index) {
        0 -> {
            println("0")
        }
        1, 2 -> {
            println("1,2")
        }
        in 4..10 -> {
            println(4..10)
        }
    }
}

在反編譯可以看出,發(fā)生了變化(變成了 if):

public final void testWhen(int index) {
   String var3;
   boolean var4;
   if (index == 0) {
      var3 = "0";
      var4 = false;
      System.out.println(var3);
   } else if (index != 1 && index != 2) {
      if (4 <= index) {
         if (10 >= index) {
            byte var5 = 4;
            IntRange var6 = new IntRange(var5, 10);
            var4 = false;
            System.out.println(var6);
         }
      }
   } else {
      var3 = "1,2";
      var4 = false;
      System.out.println(var3);
   }
}

當(dāng)我們加上了 in 4..10 條件蜓谋,那么底層則無(wú)法通過(guò) switch 來(lái)實(shí)現(xiàn)了梦皮,所以只能轉(zhuǎn)而使用了 if 來(lái)實(shí)現(xiàn)。

1.7桃焕、when fallthrough

在 Java switch 是支持 fallthrough 的:

    static void test(String value) {
        switch (value) {
            case "one":
                System.out.println("1");
            case "two":
                System.out.println("2");
                break;
            case "three":
                System.out.println(3);
                break;
        }
    }

test("one") 會(huì)輸出 1,2

但在 Kotlin 中不支持 when 的 fallthrough剑肯,因?yàn)镴ava 中在使用 switch 的如果默認(rèn)是 fallthrough ,需要顯式的加上 break观堂,這樣容易產(chǎn)生bug让网,如上面的 Java 代碼。

所以在Kotlin 中 when 是不支持 fallthrough 的师痕。

1.8溃睹、when的程序健壯性

經(jīng)過(guò)上面的分析我們知道,在 Kotlin 中使用 when 來(lái)代替 switch 或 if胰坟,除此以外丸凭,他們還有哪些不同嗎?好腕铸,我們來(lái)看下下面的一個(gè) Java switch 例子:

public void test(String value){
    switch (value){
        case "hello":
            System.out.println("hello");
            break;
        case "world":
            System.out.println("world");
            break;
        default:
            System.out.println("unknown");
    }
}

Java 基礎(chǔ)比較好的都知道,上面的代碼有可能會(huì)拋出 NullPointException铛碑,當(dāng)我們調(diào)用 test 方法的時(shí)候傳遞的參數(shù)為 null 時(shí)狠裹,就會(huì)拋出異常,因?yàn)樵?Java 中對(duì) String 進(jìn)行 switch 本質(zhì)上是使用了 string.hashCode 方法汽烦。 下面我們使用 Kotlin 來(lái)改寫(xiě)上的例子:

fun test(value: String?) {
    when (value) {
        "hello" -> println("hello")
        "world" -> println("world")
        else -> println("unknown")
    }
}

我們?cè)賮?lái)看下反編譯的結(jié)果:

public final void test(@Nullable String value) {
   String var3;
   boolean var4;
   if (value != null) {
      switch(value.hashCode()) {
      case 99162322:
         if (value.equals("hello")) {
            var3 = "hello";
            var4 = false;
            System.out.println(var3);
            return;
         }
         break;
      case 113318802:
         if (value.equals("world")) {
            var3 = "world";
            var4 = false;
            System.out.println(var3);
            return;
         }
      }
   }

   var3 = "unknown";
   var4 = false;
   System.out.println(var3);
}

從上面的反編譯后的代碼不難看出涛菠,在對(duì) switch case 之前,進(jìn)行 if 判空處理撇吞,所以就算 test 方法參數(shù)為 null 也不會(huì)出現(xiàn)空指針異常俗冻。
可以看出,相似的代碼邏輯牍颈,使用 Kotlin 來(lái)實(shí)現(xiàn)要比 Java 來(lái)實(shí)現(xiàn)要健壯的多迄薄。其實(shí)這只是 Kotlin 優(yōu)勢(shì)的冰山一角,隨著學(xué)習(xí)的深入煮岁,我想你會(huì)越來(lái)越喜歡 Kotlin讥蔽。明白這些底層原理涣易,我相信你對(duì)自己的 Kotlin 代碼越來(lái)越自信,因?yàn)槟阒滥銓?xiě)的每行 Kotlin 代碼在底層意味著什么冶伞。

1.9新症、when總結(jié)

至此,when 的介紹就要告一段落了响禽。Kotlin 使用 when 統(tǒng)一了條件判斷徒爹,當(dāng)然經(jīng)典的 if 也可以用作條件判斷,但是在 Kotlin 中更多的是使用 when 來(lái)進(jìn)行條件分支的判斷芋类,if 在 Kotlin 有它獨(dú)有的應(yīng)用的地方隆嗅。同時(shí) when 相對(duì)于 Java 中的 switch 來(lái)說(shuō),減少了很多程序員容易調(diào)入的陷阱梗肝,增加了程序的穩(wěn)定性榛瓮。除此以外,when 還有一些東西可以講巫击,這個(gè)我們留到介紹 枚舉 的時(shí)候再來(lái)細(xì)聊禀晓,同時(shí)也會(huì)結(jié)合實(shí)際工作中的一些思考 ,來(lái)聊聊 when 和 枚舉 結(jié)合使用的情況和問(wèn)題坝锰,這個(gè)相對(duì)于只介紹語(yǔ)法來(lái)說(shuō)更加重要粹懒。

2、if

if 表達(dá)式 用于條件判斷顷级,在 Kotlin 中 如果判斷分支比較多凫乖,通常使用 when 來(lái)替代 if,如:

fun test(obj: Any) {
    when (obj) {
        is String -> obj.substring(0, obj.length / 2)
        is Type2 -> ignore
        is Type3 -> ignore
    }
}

if 還可以實(shí)現(xiàn)三目運(yùn)算符:

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

二弓颈,循環(huán)

1帽芽、while,do...while

Kotlin 中的 whiledo...while 循環(huán)和 Java 沒(méi)有什么區(qū)別

while (condition) {
    /*...*/
}

do {
    /*...*/
} while (condition)

2翔冀、for循環(huán)

..操作符

for 循環(huán)的語(yǔ)法和 Java 中的循環(huán)還是有些區(qū)別

// Java for 循環(huán)
for (int i = 0; i <= 100; i++) {
    System.out.println(i);
}

// 對(duì)應(yīng) Kotlin 版本
for(i in 0..100){
    println(i)
}

使用 .. 操作符 表示一個(gè)區(qū)間导街,該區(qū)間是閉區(qū)間,包含開(kāi)始和結(jié)束的元素纤子。

in搬瑰、until操作符

然后使用 in 操作符來(lái)遍歷這個(gè)區(qū)間,這個(gè)區(qū)間是從小到大的控硼,如果開(kāi)始的數(shù)字比結(jié)尾的還要大泽论,則沒(méi)有意義

如果想要表示 半閉區(qū)間 ,即 只包含頭部元素卡乾,不包含尾部翼悴,可以使用 until 操作符:

for(i in 0 until 100){
    println(i)
}

in、downTo操作符

如果想要倒序遍歷说订,可以使用 downTo 關(guān)鍵字:

for(i in 100 downTo 0){
    println(i)
}

反編譯后:

int i = 100;
for(boolean var3 = false; i >= 0; --i) {
   boolean var4 = false;
   System.out.println(i);
}

// 其實(shí)就相當(dāng)于遞減:
for(int i = 100; i >= 0; --i) {
    System.out.println(i);
}

// 輸出 100 到 0 之間的數(shù)

遍歷的時(shí)候 步長(zhǎng)(step) 默認(rèn)是 1抄瓦,可以通過(guò) step 關(guān)鍵字來(lái)指定步長(zhǎng)

for( i in 100 downTo 0 step 2){
    println(i)
}

操作符 ..downTo 表示區(qū)間都是閉區(qū)間潮瓶,包含首尾元素的。

三钙姊、小結(jié)

如果是針對(duì)集合進(jìn)行遍歷毯辅,for 循環(huán)也可以使用 forEach 進(jìn)行遍歷

list.forEach {
    println(it.name)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市煞额,隨后出現(xiàn)的幾起案子思恐,更是在濱河造成了極大的恐慌,老刑警劉巖膊毁,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胀莹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡婚温,警方通過(guò)查閱死者的電腦和手機(jī)描焰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)栅螟,“玉大人荆秦,你說(shuō)我怎么就攤上這事×ν迹” “怎么了步绸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)吃媒。 經(jīng)常有香客問(wèn)我瓤介,道長(zhǎng),這世上最難降的妖魔是什么赘那? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任刑桑,我火速辦了婚禮,結(jié)果婚禮上募舟,老公的妹妹穿的比我還像新娘漾月。我一直安慰自己,他們只是感情好胃珍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蜓陌,像睡著了一般觅彰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钮热,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天填抬,我揣著相機(jī)與錄音,去河邊找鬼隧期。 笑死飒责,一個(gè)胖子當(dāng)著我的面吹牛赘娄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宏蛉,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼遣臼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拾并?” 一聲冷哼從身側(cè)響起揍堰,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗅义,沒(méi)想到半個(gè)月后屏歹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡之碗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年蝙眶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片褪那。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幽纷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出武通,到底是詐尸還是另有隱情霹崎,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布冶忱,位于F島的核電站尾菇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏囚枪。R本人自食惡果不足惜派诬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望链沼。 院中可真熱鬧默赂,春花似錦、人聲如沸括勺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疾捍。三九已至奈辰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乱豆,已是汗流浹背奖恰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瑟啃。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓论泛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛹屿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子屁奏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一、類(lèi) 1.1 類(lèi)聲明 Kotin中使用關(guān)鍵字class聲明類(lèi)蜡峰,且默認(rèn)是public了袁。如果一個(gè)類(lèi)沒(méi)有類(lèi)體,可以省略...
    者文_閱讀 1,289評(píng)論 0 1
  • 前言 Google 在2017年 I/O 大會(huì)上宣布,Kotlin 正式成為 Android 的一級(jí)開(kāi)發(fā)語(yǔ)言油航,和 ...
    sweetying閱讀 1,430評(píng)論 0 5
  • 文章來(lái)源 Kotlin 系統(tǒng)入門(mén)到進(jìn)階 視頻教程 這是什么崭庸?這是作者最新制作的系統(tǒng)講解 Kotlin 的視頻教程,...
    夢(mèng)_之_旅閱讀 1,999評(píng)論 0 3
  • Kotlin的優(yōu)勢(shì) 代碼簡(jiǎn)潔高效谊囚、強(qiáng)大的when語(yǔ)法怕享,不用寫(xiě)分號(hào)結(jié)尾,findViewById光榮退休镰踏,空指針安全...
    Windy_816閱讀 1,287評(píng)論 1 6
  • 前言 人生苦多函筋,快來(lái) Kotlin ,快速學(xué)習(xí)Kotlin奠伪! 什么是Kotlin跌帐? Kotlin 是種靜態(tài)類(lèi)型編程...
    任半生囂狂閱讀 26,201評(píng)論 9 118