Kotlin之控制語句和表達(dá)式

原文鏈接 Kotlin Controls and Expressions

有結(jié)果返回的是表達(dá)式,沒有返回的稱之為語句馆类,語句最大的問題是它沒有返回值混聊,那么想要保存結(jié)果就必然會產(chǎn)生副作用,比如改變變量乾巧。很多時候這是不夠方便的句喜,并且在多線程條件下,這甚至是不安全的沟于。Kotlin中咳胃,為了加強線程安全性和方便并發(fā)和異步,因此絕大多數(shù)語句都是表達(dá)式旷太。

[圖片上傳失敗...(image-b0f37e-1699879436422)]

分支表達(dá)式

Kotlin中沒有三元條件符(a > b ? a : b)展懈,但它的條件分支都是表達(dá)式,可以直接放在賦值符的右邊供璧,或者用在return語句中存崖。

if表達(dá)式

它是一個兩個分支的表達(dá)式,是有返回值的:

val maxV = if (a > b) a else b

當(dāng)然了睡毒,把它當(dāng)作常規(guī)的語句來使用也是沒有問題的:

var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

when表達(dá)式

當(dāng)超過2個分支時来惧,if就不能用了,這時可以用when表達(dá)式演顾,它支持多個分支供搀,類似于其他語言中的switch:

when (x) {
     1 -> println("it is 1")
     2 -> println("it is 2")
     else -> {
          println("it is neight 1 nor 2")
     }
}

需要注意的是隅居,每一行是一個條件,并不是單單指參數(shù)與其相等葛虐,比如:

when (x) {
     in 1..5 -> println("Less than 5 bigger than 1")
     x.isEven() -> println("it is even")
     else -> println("It is neither even or less than 5")
}

當(dāng)然军浆,最重要的是when是一個表達(dá)式,可以直接用在賦值符的右邊挡闰,或者當(dāng)參數(shù)傳乒融,或者用在return中

fun Request.getBody() =
    when (val response = executeRequest()) {
        is Success -> response.body
        is HttpError -> throw HttpException(response.status)
    }

這里的when就是函數(shù)的返回值,可以看到when是一個表達(dá)式摄悯,它會返回一個值赞季,這個值直接作為函數(shù)的返回值

從這幾個示例可以看出when表達(dá)式相當(dāng)強大比其他語言的switch要強大許多奢驯,并且可以直接當(dāng)作返回值申钩,當(dāng)需要超過2個條件分支時就可以使用when表達(dá)式。

循環(huán)語句

循環(huán)是語句瘪阁,與其他語言也差不多撒遣。

while loop

while (x < 10) {
    println(x)
    x++
}

屁股向后式do-while loop

do {
  x = poll()
} while (x < 10)

強大的for loop

這個是最強大,也是最常用的循環(huán)語句遍歷數(shù)組管跺,集合和固定步長時的首選义黎。

for (item in collection) print(item)

這里的collection可以是數(shù)組和集合(列表和Set)。嚴(yán)格來說只要collection類型實現(xiàn)了iterator()和next()豁跑,就可以在for loop中使用廉涕。

for加上range,可以非常強大:

for (i in 1..10) // = for (int i = 1; i <= 10; i++)
for (i in 0 until 10) // = for (int i = 0; i < 10; i++)
for (i in 9 downTo 0) // = for (int i = 9; i >= 0; i--)
for (i in 0 until 10 step 2) // = for (int i = 0; i < 10; i += 2)

如果是數(shù)組或者列表艇拍,但又必須要用索引狐蜕,也可以直接來:

for (i in array.indices) {
     println(array[i]) // 'i' is the index
}

其實有更好的方式:

for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

其實吧,Kotlin是多范式編程語言卸夕,天生支持函數(shù)式編程层释,多數(shù)情況下不建議直接上for loop,而是用函數(shù)式方式的forEach快集,數(shù)組和集合都支持forEach的:

array.forEach { println(it) }

終止語句

當(dāng)想提前退出函數(shù)的執(zhí)行贡羔,或者循環(huán)時,就需要用到終止語句碍讨,有三種return, break和continue治力。

return終止函數(shù)執(zhí)行

這個都比較熟悉,常規(guī)的用法都是一樣的勃黍,可以提前退出函數(shù):

fun plot(x: Int) {
     if (x < 1) {
         return -1
     }
     ...
     return y
}

但當(dāng)有嵌套的lambda時宵统,如不特別指定,return會退出外層的函數(shù),而不是像想當(dāng)然的退出lambda马澈,比如:

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return // non-local return directly to the caller of foo()
        print(it)
    }
    println("this point is unreachable")
}

這個不是終止lambda的執(zhí)行瓢省,而是直接退出函數(shù)foo的執(zhí)行。如果想解決呢痊班,即也退出遍歷的lambda有三種方案:

  • 使用標(biāo)簽
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
        print(it)
    }
    print(" done with explicit label")
}
  • 使用隱式標(biāo)簽勤婚,也即遍歷的方法當(dāng)作標(biāo)簽
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
        print(it)
    }
    print(" done with implicit label")
}
  • 使用匿名函數(shù)而不是lambda,匿名函數(shù)與常規(guī)函數(shù)體效力一樣涤伐,所以return只在函數(shù)體內(nèi)生效
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
        if (value == 3) return  // local return to the caller of the anonymous function - the forEach loop
        print(value)
    })
    print(" done with anonymous function")
}

這三種方式馒胆,如果非要使用,建議使用方式二凝果,用自帶的隱式label祝迂,因為比較方便,可讀性也不差器净。

但型雳,非常不建議如此使用return語句,這本是應(yīng)該避免的問題山害,lambda多半是用在函數(shù)式遍歷和處理纠俭,在lambda里面提加return本就是非常奇怪的事情。因為如果某些條件不滿足浪慌,想不執(zhí)行此lambda冤荆,應(yīng)該用filter啊,而不是笨拙的非要在lambda中去終止:

fun foo() {
    listOf(1, 2, 3, 4, 5)
        .filter(i -> i != 3)
        .forEach { println(it) }
    print("You can do whatever you like here.")
}

循環(huán)的終止

break終止當(dāng)前循環(huán)眷射,continue則是跳過當(dāng)前循環(huán)的當(dāng)前步驟匙赞,直接跳到下一次迭代。這兩個的常規(guī)使用與其他語言是一樣的妖碉。

但對于break,一般來說有一個痛點芥被,就是當(dāng)有循環(huán)嵌套時欧宜,break只能終止一層,如果想終止所有循環(huán)時拴魄,只能再手動的加條件去判斷冗茸,然后再一層一層的break,比如:

for (i in 0 until 10) {
   var found = false
   for (j in i until 10) {
       if (array[i] + array[j] == target) {
           found = true
           break // only break inner for loop
       }
   }
   if (found) {
       break // this break outer for loop
   }
}

這多少有點笨拙和丑陋匹中,Kotlin有更優(yōu)雅的解決方式夏漱,就是引入了標(biāo)簽label,可以給循環(huán)加上標(biāo)簽顶捷,在break時可以指定標(biāo)簽挂绰,同樣是上面的情況,可以這樣做:

loop@ for (i in 0 until 10) {
   for (j in i until 10) {
       if (array[i] + array[j] == target) {
          break @loop // break all loops easily
       }
   }
}

其實吧服赎,這玩意兒跟當(dāng)年的goto是一樣的葵蒂,雖然可行交播,但不建議多使用標(biāo)簽多了以后會讓程序的執(zhí)行更加的混亂践付,試想假如在層層循環(huán)中break錯了某個標(biāo)簽秦士,調(diào)試的難度是相當(dāng)大的。更多的時候需要仔細(xì)想想有沒有更好的遍歷方式永高,而不是靠標(biāo)簽來救命隧土。

原創(chuàng)不易,打賞命爬,點贊曹傀,在看收藏遇骑,分享 總要有一個吧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卖毁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子落萎,更是在濱河造成了極大的恐慌亥啦,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件练链,死亡現(xiàn)場離奇詭異翔脱,居然都是意外死亡,警方通過查閱死者的電腦和手機媒鼓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門届吁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绿鸣,你說我怎么就攤上這事疚沐。” “怎么了潮模?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵亮蛔,是天一觀的道長。 經(jīng)常有香客問我擎厢,道長究流,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任动遭,我火速辦了婚禮芬探,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘厘惦。我一直安慰自己偷仿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炎疆,像睡著了一般卡骂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上形入,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天全跨,我揣著相機與錄音,去河邊找鬼亿遂。 笑死浓若,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛇数。 我是一名探鬼主播挪钓,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼耳舅!你這毒婦竟也來了碌上?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浦徊,失蹤者是張志新(化名)和其女友劉穎馏予,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盔性,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡霞丧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冕香。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛹尝。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖悉尾,靈堂內(nèi)的尸體忽然破棺而出突那,到底是詐尸還是另有隱情,我是刑警寧澤构眯,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布陨收,位于F島的核電站,受9級特大地震影響鸵赖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拄衰,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一它褪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翘悉,春花似錦茫打、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轮洋。三九已至,卻和暖如春抬旺,著一層夾襖步出監(jiān)牢的瞬間弊予,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工开财, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留汉柒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓责鳍,卻偏偏與公主長得像碾褂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子历葛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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