kotlin學(xué)習(xí)筆記之lambda

語法

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

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

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

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

在作用域中訪問變量

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

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

你可能會問這是什么原理。當(dāng)你捕捉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被用作事件處理器或者用在其他異步執(zhí)行的情況,對局部變量的修改只會在lambda執(zhí)行的時候發(fā)生。

成員引用

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

val getAge = Person::age

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

fun salute() = println("salute")

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

集合函數(shù)式API

filter

filter函數(shù)遍歷集合并選出應(yīng)用給定lambda后會返回true的哪些元素:

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

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

map

map函數(shù)對集合中的每一個元素應(yīng)用給定的函數(shù)并把結(jié)果收集到一個新的集合。

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

map函數(shù)可以變換元素。

all

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

fun main(args: Array<String>) {
    // 假設(shè)存在一個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:把列表轉(zhuǎn)換成分組的map

假設(shè)你需要把所有元素按照不同的特征劃分成不同的分組,返回結(jié)果是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>)

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

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容