Kotlin之Lambda表達(dá)式和成員引用

Lambda介紹:作為函數(shù)參數(shù)的代碼塊

用匿名內(nèi)部類實(shí)現(xiàn)監(jiān)聽器

<!--Java-->
button.setOnClickListener(new OnClickListener(){
       override
       public void onClick(View view){
          <!-- 點(diǎn)擊后執(zhí)行的動(dòng)作-->
       }
    }
);

現(xiàn)在用Kotlin的Lambda表達(dá)式來(lái)替換匿名內(nèi)部類

button.setOnClickListener{<!--點(diǎn)擊后執(zhí)行的動(dòng)作-->}

Lambda和集合

先看一個(gè)例子

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

然后創(chuàng)建一個(gè)Person集合撕予,并找出集合中年齡最大的那個(gè)

val list = listOf(Person("Alice",29),Person("Bob",31))
println(list.maxBy{it.age})
Person{name=Bob,age=31}

如上使用了Kotlin的庫(kù)函數(shù)隘膘,maxBy函數(shù)可以在任何集合上調(diào)用愿汰,且只需要一個(gè)實(shí)參:一個(gè)函數(shù)粹排,指定比較哪個(gè)值來(lái)找到最大值桨啃,而花括號(hào)中的代碼{it.age}就是實(shí)現(xiàn)了這個(gè)邏輯的lambda

如果lambda剛好是屬性的委托忍燥,可以用成員引用代替

list.maxBy(Person::age)

Lambda表達(dá)式語(yǔ)句

還可以把lambda表達(dá)式存儲(chǔ)在一個(gè)變量中

val sum = { x:Int,y:Int -> x+y }
println(sum(1,2))

還可以直接調(diào)用lambda表達(dá)式

{println(42)}()

但是這樣的語(yǔ)法毫無(wú)可讀性墓卦,也沒有什么意義掷贾,如果你確實(shí)需要把一小段代碼封閉在一個(gè)代碼塊中睛榄,可以使用庫(kù)函數(shù)run來(lái)執(zhí)行傳給它的lambda

run { println(42) }

再回到上面的例子

val list = listOf(Person("Alice",29),Person("Bob",31))
println(list.maxBy{it.age})

如果不用簡(jiǎn)明的語(yǔ)法重寫這個(gè)例子,你會(huì)得到下面的代碼

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

這個(gè)代碼就一目了然了想帅,花括號(hào)里面的代碼片段是lambda表達(dá)式场靴,把它作為實(shí)參傳遞給函數(shù)。這個(gè)lambda接受一個(gè)Person的參數(shù)并返回它的年齡

這個(gè)代碼還可以簡(jiǎn)化港准,如果lambda表達(dá)式是函數(shù)調(diào)用的最后一個(gè)實(shí)參旨剥,它可以放到括號(hào)的外面

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

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

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

省略lambda參數(shù)類型浅缸,和局部變量一樣轨帜,如果lambda參數(shù)的類型可以被推導(dǎo)出來(lái),你就不需要顯示地指定它衩椒。這里以maxBy函數(shù)為例蚌父,其參數(shù)的類型始終和集合中元素的類型相同

list.maxBy { p -> p.age }

使用默認(rèn)參數(shù)類型哮兰,僅在實(shí)參名稱沒有顯示地指定時(shí)這個(gè)默認(rèn)的名稱才會(huì)生成

list.maxBy{ it.age }

注意: it約定能大大縮短你的代碼,但你不應(yīng)該濫用它苟弛。尤其在嵌套lambda的情況下喝滞,最后顯示地聲明每個(gè)lambda的參數(shù)。否則很難搞清楚it引用的到底是哪個(gè)值嗡午。

此外,lambda表達(dá)式還可以包含更多的語(yǔ)句

val sum = { x:Int,y:Int -> 
    println("Computing the sum of $x and $y...")
    x+y
}

println(sum(1,2)

Computing the sum of 1 and 2...
3

在作用域中訪問(wèn)變量

當(dāng)在函數(shù)中聲明一個(gè)匿名內(nèi)部類的時(shí)候冀痕,在匿名內(nèi)部類中可以引用函數(shù)的參數(shù)和局部變量荔睹。如果函數(shù)內(nèi)部使用lambda,也可以訪問(wèn)這個(gè)函數(shù)的參數(shù)

fun printMessageWithPrefix(messages:Collec    tion<String>,prefix:String){
        messages.forEach {<!--接收l(shuí)ambda作為實(shí)參-->
        println("$prefix $it") <!--在lambda中訪問(wèn)prefix參數(shù)-->
    }
}

這里Kotlin和Java的區(qū)別就是言蛇,在Kotlin中不會(huì)僅限于訪問(wèn)final變量僻他,在lambda內(nèi)部也可以修改這些變量

成員引用

如果你想要當(dāng)做參數(shù)傳遞的代碼已經(jīng)被定義成了函數(shù),那么你可以將這個(gè)函數(shù)轉(zhuǎn)換成值腊尚,如下使用::運(yùn)算符來(lái)轉(zhuǎn)換

val getAge = Person::age

這種表達(dá)式被稱為成員引用吨拗,它提供簡(jiǎn)明語(yǔ)法,來(lái)創(chuàng)建一個(gè)調(diào)用單個(gè)方法或這訪問(wèn)單個(gè)屬性的函數(shù)值婿斥。雙冒號(hào)把類名稱和你要引用的成員名稱隔開

如下這個(gè)lambda表達(dá)式

val getAge = { person:Person -> person.age }

成員引用和調(diào)用函數(shù)的lambda具有一樣的類型劝篷,所以可以相互轉(zhuǎn)換

list.maxBy(Person::age)

還可以引用頂層函數(shù),這種情況省略了類名稱民宿,直接以::開頭娇妓。成員引用::salute被當(dāng)作實(shí)參傳遞給庫(kù)函數(shù)run

fun salute() = println("Salute!")
run (::salute)
Salute!

如果lambda要委托給一個(gè)接收多個(gè)參數(shù)的函數(shù),提供成員引用代替它將會(huì)非常方便

val action = {person:Person,message:String -> sendEmail(person,message)}

val nextAction = ::sendEmail
調(diào)用
nextAction(...,...)

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

val createPerson = ::Person <!--創(chuàng)建`Person`實(shí)例的動(dòng)作被保存成了值-->
val person = createPerson("kdp",25)
println(person)

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

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

綁定引用

Kotlin1.1允許你使用成員引用語(yǔ)法捕捉特定實(shí)例對(duì)象上的方法引用

val p = Person("Dmitry",34)
val dmitrysAgeFunction = p::age
println(dmitrysAgeFunction())

注意:dmitrysAgeFunction是一個(gè)零函數(shù)的參數(shù)哈恰,在Kotlin1.1之前,你需要顯示地寫出lambda{p.age}志群,而不是使用綁定成員引用p::age

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末着绷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锌云,更是在濱河造成了極大的恐慌荠医,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桑涎,死亡現(xiàn)場(chǎng)離奇詭異子漩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)石洗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門幢泼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人讲衫,你說(shuō)我怎么就攤上這事缕棵》醢啵” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵招驴,是天一觀的道長(zhǎng)篙程。 經(jīng)常有香客問(wèn)我,道長(zhǎng)别厘,這世上最難降的妖魔是什么虱饿? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮触趴,結(jié)果婚禮上氮发,老公的妹妹穿的比我還像新娘。我一直安慰自己冗懦,他們只是感情好爽冕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著披蕉,像睡著了一般颈畸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上没讲,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天眯娱,我揣著相機(jī)與錄音,去河邊找鬼爬凑。 笑死困乒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贰谣。 我是一名探鬼主播娜搂,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吱抚!你這毒婦竟也來(lái)了百宇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤秘豹,失蹤者是張志新(化名)和其女友劉穎携御,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體既绕,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啄刹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凄贩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誓军。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疲扎,靈堂內(nèi)的尸體忽然破棺而出昵时,到底是詐尸還是另有隱情捷雕,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布壹甥,位于F島的核電站救巷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏句柠。R本人自食惡果不足惜浦译,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溯职。 院中可真熱鬧精盅,春花似錦、人聲如沸缸榄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甚带。三九已至,卻和暖如春佳头,著一層夾襖步出監(jiān)牢的瞬間鹰贵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工康嘉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碉输,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓亭珍,卻偏偏與公主長(zhǎng)得像敷钾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肄梨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359