kotlin學習筆記之lambda

語法

一個lambda把一小段行為進行編碼,你能把它當作值到處傳遞。它可以被獨立地聲明并存儲到一個變量中。但是更常用的還是直接聲明它并傳遞給函數。

// 箭頭前面的是參數,箭頭后面的是函數體
// 始終在花括號內
{ x: Int, y: Int -> x + y }

// 可以把lambda表達式存儲在一個變量中,把這個變量當作普通函數對待(即通過相應實參調用它)
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2))

people.maxBy() { p: People -> p.age }
//當lambda是函數唯一的實參時,還可以去掉調用代碼中的空括號對
people.maxBy { p: People -> p.age }

在作用域中訪問變量

和Java不一樣,kotlin允許在lambda內部訪問非fianl變量甚至修改它們。從lambda內訪問外部變量,我們稱這些變量被lambda捕捉。

注意,默認情況下,局部變量的聲明周期被限制在聲明這個變量的函數中。但是如果它被lambda捕捉了,使用這個變量的代碼可以被存儲并稍后再執行。

你可能會問這是什么原理。當你捕捉final變量時,它的值和使用這個值的lambda代碼一起存儲。而非final變量來說,它的值封裝在一個特殊的包裝器中,這樣你就可以改變這個值,而對這個包裝器的引用會和lambda代碼一起存儲。

fun printProblemCounts(responses: Collection<String>) {
    var clientErrors = 0
    var serverErrors = 0

    responses.forEach {
        if (it.startsWith("4")) {
            clientErrors++
        } else if (it.startsWith("5")) {
            serverErrors++
        }
    }

    println("$clientErrors client errors, $serverErrors server errors.")
}

fun main(args: Array<String>) {
    val responses = listOf("200 ok", "418 I'm a teapot"
    , "500 Internal server error")
    printProblemCounts(responses)
}

這里有一個重要的注意事項,如果lambda被用作事件處理器或者用在其他異步執行的情況,對局部變量的修改只會在lambda執行的時候發生。

成員引用

把函數轉換成一個值,使用::運算符來轉換。這種表達式稱為成員引用,它提供一個調用單個方法或者訪問單個屬性的函數值。雙冒號把類名稱與你要應用的成員(一個方法或者一個屬性)名稱分隔開:

val getAge = Person::age

可以引用頂層函數(不是類成員):

fun salute() = println("salute")

fun main(args: Array<String>) {
        run(::salute)
}

集合函數式API

filter

filter函數遍歷集合并選出應用給定lambda后會返回true的哪些元素:

fun main(args: Array<String>) {
      val list = listOf(1,2,3,4)
      // 只有偶數留下來
      println(list.filter { it % 2 == 0 })
       // [2, 4]
}

filter函數可以從集合中移除你不想要的元素,但是它并不會改變這些元素。

map

map函數對集合中的每一個元素應用給定的函數并把結果收集到一個新的集合。

fun main(args: Array<String>) {
        val list = listOf(1,2,3,4)
        println(list.map { it * it })
        // [1, 4, 9, 16]
}

map函數可以變換元素。

all

檢查集合中所有元素是否符合某個條件(或者它的變種,是否存在符合的元素)。

fun main(args: Array<String>) {
    // 假設存在一個Persion類
    val canBeInClub27 = { p: Persion -> p.age <= 27 }
    val people = listOf(Persion("a", 27), Persion("b", 31))
    // 年齡是否都小于27
    println(people.all(canBeInClub27))
    // println(people.all { p: Persion -> p.age <= 27 })
    // false
}

any

檢查集合中任意元素符合某個元素。

fun main(args: Array<String>) {
    val list = listOf(1,2,3,4)
    println(list.any { it != 3 })
    // true
}

count

檢查集合中有多少元素滿足判斷式。

fun main(args: Array<String>) {
    val list = listOf(1,2,3,4)
    println(list.count{ it != 3 })
    // 3
}

find

在集合中找到滿足判斷式的的元素,但不是所有元素,它按順序查找。

fun main(args: Array<String>) {
    val list = listOf(1,2,3,4)
    println(list.find{ it != 3 })
    // 1
}

groupBy:把列表轉換成分組的map

假設你需要把所有元素按照不同的特征劃分成不同的分組,返回結果是Map<K, List<T>>類型。例如,你想把人按年齡分組,相同年齡的人放在一組。

fun main(args: Array<String>) {
    val list = listOf<Person>(Person("a",10),Person("b",10),Person("c",15))
    println(list.groupBy { it.age })
    // {10=[name=a,age=10, name=b,age=10], 15=[name=c,age=15]}
}

class Person(val name: String, val age: Int) {
    override fun toString(): String {
        return "name=$name,age=$age"
    }
}

flatMap和flatten:處理嵌套集合中的元素

如下:

class Book(val title: String, val authors: List<String>)

// 每本書都可能有一個或者多個作者,可以統計出圖書館中的所有作者的set
// books是集合
books.flatMap { it.authors }.toSet()

flatMap函數做了兩件事情:首先根據作為實參給定的函數對集合中的每個元素做變換(或者說映射),然后把多個列表合并(或者說平鋪)成一個列表。

如果你不需要做任何變換,只是需要平鋪一個集合,可以使用flatten函數。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容