Kotlin Lambda 表達(dá)式摘要

基本語(yǔ)法

people.maxBy({ p: Person -> p.age })

如果 lambda 表達(dá)式是函數(shù)調(diào)用的最后一個(gè)實(shí)參田度,它可以放到括號(hào)的外邊多望。

people.maxBy() { p: Person -> p.age }

當(dāng) lambda 是函數(shù)唯一的實(shí)參時(shí)善延,你還可以去掉調(diào)用代碼中的空括號(hào)對(duì)贷痪。

people.maxBy { p: Person -> p.age }

如果 lambda 參數(shù)的類型可以被推導(dǎo)出來(lái)腮出,你就不需要顯式地指定它帖鸦。

people.maxBy { p -> p.age } // 推導(dǎo)出參數(shù)類型

最后簡(jiǎn)化使用默認(rèn)參數(shù)名稱it代替命名參數(shù)。如果當(dāng)前上下文期望的是只有一個(gè)參數(shù)的 lambda 且這個(gè)參數(shù)的類型可以推斷出來(lái)胚嘲,就會(huì)生成這個(gè)名稱作儿。

people.maxBy { it.age } // “it”是自動(dòng)生成的參數(shù)名稱

如果你用變量存儲(chǔ) lambda,那么就沒(méi)有可以推斷出參數(shù)類型的上下文馋劈,所以你必須顯式地指定參數(shù)類型:

>>> val getAge = { p: Person -> p.age }
>>> people.maxBy(getAge)

訪問(wèn)變量

Kotlin 和 Java 的一個(gè)顯著區(qū)別就是攻锰,在 Kotlin 中你不會(huì)僅限于訪問(wèn) final 變量。在 lambda 內(nèi)部你也可以修改這些變量妓雾。

fun printProblemCounts(responses: Collection<String>) {
    var clientErrors = 0 // 聲明將在 lambda 內(nèi)部訪問(wèn)的變量
    var serverErrors = 0
    responses.forEach {
        if (it.startsWith("4")) {
            clientErrors++ // 在 lambda 里修改變量
        } else if (it.startsWith("5")) {
            serverErrors++
        }
    }
    println("$clientErrors client errors, $serverErrors server errors")
}

成員引用

Kotlin 和 Java 8 一樣口注,如果你把函數(shù)轉(zhuǎn)換成一個(gè)值,你就可以傳遞它君珠。你使用::運(yùn)算符來(lái)轉(zhuǎn)換寝志,這種表達(dá)式稱為成員引用

val getAge = Person::age

你還可以引用頂層函數(shù)(不是類的成員):

fun salute() = println("Salute!")
>>> run(::salute) // 引用頂層函數(shù)
Salute!

注意你還可以用同樣的方式引用擴(kuò)展函數(shù):

fun Person.isAdult() = age >= 21
val predicate = Person::isAdult

你可以用構(gòu)造方法引用存儲(chǔ)或者延期執(zhí)行創(chuàng)建類實(shí)例的動(dòng)作。構(gòu)造方法引用的形式是在雙冒號(hào)后指定類名稱

data class Person(val name: String, val age: Int)

>>> val createPerson = ::Person // 創(chuàng)建“Person”實(shí)例的動(dòng)作被保存成了值
>>> val p = createPerson("Alice", 29)
>>> println(p)
Person(name=Alice, age=29)

使用 Java 函數(shù)式接口

在 Java 中我們隨處可見(jiàn)這樣的代碼

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        ...
    }
});

在 Kotlin 中策添,你可以傳遞一個(gè) lambda材部,代替這個(gè)實(shí)例

button.setOnClickListener { view -> ... }

但是你需要注意,只有在調(diào)用 Java 中的類似函數(shù)時(shí)才能縮寫(xiě)成這樣簡(jiǎn)單的lambda唯竹,如果你調(diào)用的是Kotlin 的函數(shù)乐导,你需要在 lambda 前面顯示的加上類型名字,強(qiáng)制將 lambda 轉(zhuǎn)換成對(duì)應(yīng)的接口類型

 setRunnable(Runnable { println("All done!") })

OnClickListener接口只有一個(gè)抽象方法浸颓,這種接口被稱為函數(shù)式接口物臂,或者SAM 接口,SAM 代表單抽象方法[譯注:_S_ingle _A_bstract _M_ethod]产上。Java API 中隨處可見(jiàn)像RunnableCallable這樣的函數(shù)式接口棵磷。

當(dāng)然我們也可以通過(guò)匿名對(duì)象來(lái)實(shí)現(xiàn)

button.setOnClickListener(object : OnClickListener { // 把對(duì)象表達(dá)式作為函數(shù)式接口的實(shí)現(xiàn)傳遞
    override fun onClick(View v) {
        ...
    }
})

不過(guò)很顯然,這樣的寫(xiě)法并不簡(jiǎn)潔晋涣。

還有一個(gè)重要的不同是仪媒,當(dāng)你顯式地聲明對(duì)象時(shí),每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的實(shí)例谢鹊。使用 lambda 的情況不同:如果 lambda 沒(méi)有訪問(wèn)任何來(lái)自定義它的函數(shù)的變量算吩,相應(yīng)的匿名類實(shí)例可以在多次調(diào)用之間重用:

button.setOnClickListener { view -> ... }// 整個(gè)程序只會(huì)創(chuàng)建一個(gè) OnClickListener 的實(shí)例

然后留凭,如果 lambda 從包圍它的作用域里捕捉了變量,每次調(diào)用就不再可能重用同一個(gè)實(shí)例了偎巢。這種情況下蔼夜,每次調(diào)用時(shí)編譯器都要?jiǎng)?chuàng)建一個(gè)新對(duì)象,其中存儲(chǔ)著被捕捉的變量的值压昼。

fun handleComputation(id: String) { // lambda 會(huì)捕捉”id“這個(gè)變量
    postponeComputation(1000) { println(id) } // 每次 handleComputation 調(diào)用時(shí)都創(chuàng)建一個(gè) Runnable 的新實(shí)例
}

SAM 構(gòu)造方法顯式地把 lambda 轉(zhuǎn)換成函數(shù)式接口

fun createAllDoneRunnable(): Runnable {
    return Runnable { println("All done!") }
}
>>> createAllDoneRunnable().run()
All done!
val listener = OnClickListener { view ->
    val text = when (view.id) { // 使用 view.id 來(lái)判斷點(diǎn)擊的是哪個(gè)按鈕
        R.id.button1 -> "First button"
        R.id.button2 -> "Second button"
        else -> "Unknown button"
    }
    toast(text) // 把“text”的值顯示給用戶
}
button1.setOnClickListener(listener)
button2.setOnClickListener(listener)

“with”函數(shù)

來(lái)看一個(gè)例子:

fun alphabet(): String {
    val result = StringBuilder()
    for (letter in 'A'..'Z') {
         result.append(letter)
    }
    result.append("\nNow I know the alphabet!")
    return result.toString()
}
>>> println(alphabet())
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Now I know the alphabet!

使用 with函數(shù)改造

fun alphabet(): String {
    val stringBuilder = StringBuilder()
    return with(stringBuilder) { // 指定接收者的值求冷,你會(huì)調(diào)用它的方法
        for (letter in 'A'..'Z') {
            this.append(letter) // 通過(guò)顯式的“this”來(lái)調(diào)用接收者值的方法
        }
        append("\nNow I know the alphabet!") // 省掉“this”也可以調(diào)用方法,
        this.toString() // 從 lambda 返回值
    }
}

進(jìn)一步改造

fun alphabet() = with(StringBuilder()) {
    for (letter in 'A'..'Z') {
        append(letter)
    }
    append("\nNow I know the alphabet!")
    toString()
}

with返回的值是執(zhí)行 lambda 代碼的結(jié)果巢音。該結(jié)果就是 lambda 里的最后一個(gè)表達(dá)式(的值)。

但有時(shí)候你想返回的是接收者對(duì)象尽超,而不是執(zhí)行 lambda 的結(jié)果官撼。這時(shí)apply庫(kù)函數(shù)就派上用場(chǎng)了。

“apply”函數(shù)

apply函數(shù)幾乎和with函數(shù)一模一樣似谁;唯一的區(qū)別是apply始終會(huì)返回作為實(shí)參傳遞給它的對(duì)象(換句話說(shuō)傲绣,接收者對(duì)象)。讓我們?cè)僖淮沃貥?gòu)alphabet函數(shù)巩踏,這一次用的是apply秃诵。

fun alphabet() = StringBuilder().apply {
    for (letter in 'A'..'Z') {
        append(letter)
    }
    append("\nNow I know the alphabet!")
}.toString()

另外,在kotlin標(biāo)準(zhǔn)庫(kù)中查看apply函數(shù)的源碼

inline fun <T> T.apply(block: T.() -> Unit): T

你會(huì)發(fā)現(xiàn)T.() -> Unit塞琼,我們平時(shí)定義函數(shù)類型參數(shù)難道不是() -> Unit嗎菠净?

這里是有區(qū)別的,前者表示帶有接受者的函數(shù)類型彪杉,也就是在這個(gè)函數(shù)內(nèi)部的this表示的是接受者實(shí)例毅往。而后者使用的this表示包含這個(gè)函數(shù)的外部類。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末派近,一起剝皮案震驚了整個(gè)濱河市攀唯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渴丸,老刑警劉巖侯嘀,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谱轨,居然都是意外死亡戒幔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)土童,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)溪食,“玉大人,你說(shuō)我怎么就攤上這事娜扇〈砦郑” “怎么了栅组?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)枢析。 經(jīng)常有香客問(wèn)我玉掸,道長(zhǎng),這世上最難降的妖魔是什么醒叁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任司浪,我火速辦了婚禮,結(jié)果婚禮上把沼,老公的妹妹穿的比我還像新娘啊易。我一直安慰自己,他們只是感情好饮睬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布租谈。 她就那樣靜靜地躺著,像睡著了一般捆愁。 火紅的嫁衣襯著肌膚如雪割去。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天昼丑,我揣著相機(jī)與錄音呻逆,去河邊找鬼。 笑死菩帝,一個(gè)胖子當(dāng)著我的面吹牛咖城,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呼奢,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼酒繁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了控妻?” 一聲冷哼從身側(cè)響起州袒,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弓候,沒(méi)想到半個(gè)月后郎哭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菇存,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年夸研,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片依鸥。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亥至,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姐扮,我是刑警寧澤絮供,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站茶敏,受9級(jí)特大地震影響壤靶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惊搏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一贮乳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恬惯,春花似錦向拆、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至葡兑,卻和暖如春奖蔓,著一層夾襖步出監(jiān)牢的瞬間赞草,已是汗流浹背讹堤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厨疙,地道東北人洲守。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像沾凄,于是被迫代替她去往敵國(guó)和親梗醇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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

  • 前言 人生苦多撒蟀,快來(lái) Kotlin 叙谨,快速學(xué)習(xí)Kotlin! 什么是Kotlin保屯? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,201評(píng)論 9 118
  • 寫(xiě)在開(kāi)頭:本人打算開(kāi)始寫(xiě)一個(gè)Kotlin系列的教程手负,一是使自己記憶和理解的更加深刻,二是可以分享給同樣想學(xué)習(xí)Kot...
    胡奚冰閱讀 1,245評(píng)論 0 6
  • 原文鏈接:https://github.com/EasyKotlin 值就是函數(shù)姑尺,函數(shù)就是值竟终。所有函數(shù)都消費(fèi)函數(shù),...
    JackChen1024閱讀 5,965評(píng)論 1 17
  • 2018-05-16第三十篇原創(chuàng)文章 今天天氣太熱切蟋,還刮起了妖風(fēng)统捶。但并不感覺(jué)到一絲涼爽,室外就是一個(gè)蒸籠,室內(nèi)開(kāi)著...
    骨羽閱讀 1,252評(píng)論 0 3
  • hi犬绒,你們好。我是小白訓(xùn)練營(yíng)45期24班六組12號(hào)W. 像一切有老師有作業(yè)的學(xué)習(xí)一樣兑凿,我迎來(lái)了小白的畢業(yè)凯力,在大神的...
    叫老吳的閱讀 296評(píng)論 1 0