Kotlin之集合的函數式API(Lambda)

集合的函數式 API 有很多種,我們只重點學習函數式 API 的結構,也就是 Lambda 表達式的語法結構

要求:在集合中找出名字最長的那個值:

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    var maxLength = ""
    for (name in list) {
        if (name.length > maxLength.length) {
            maxLength = name
        }
    }
    print("max is $maxLength")
}

以上雖然說是一段很清晰的代碼,但是如果使用函數式編程,可以變的更加簡單:

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    val maxLength = list.maxBy { it.length }
    print("max is $maxLength")
}

以上就是函數式 API 的用法,只用一行代碼就可以找到最長的名字,現在看可能還會摸不着頭腦,那是因爲我們還沒有學習 Lambda 表達式的語法結構,那就上 Lambda 的語法結構

Lambda 的定義

Lambda 是一小段可以作爲參數傳遞的代碼

一般來說,我們向某個函數傳參時只能傳入變量,而藉助 Lambda 卻可以傳入一小段代碼,那麼多長才算一小段代碼呢?Kotlin 沒有對此進行限制,但通常不建議在 Lambda 中寫太長的代碼,否則可能會影響代碼的可讀性

Lambda 語法結構

{ 參數名1: 參數類型, 參數名2: 參數類型 -> 函數體 }

首先最外層是一個大括號,如果有數據傳入到 Lambda 表達式當中的話,我們還需要聲明參數列表,參數列表的結尾使用的是 -> 符號,表示參數列表的結束以及函數體的開始,並且最後一行會自動作爲 Lambda 的返回值

在很多情況下,我們不需要使用 Lambda 的完整的語法結構,而是有很多種簡化的寫法,但是簡化版的似乎更難理解,我們一步步推倒簡化版的由來,從而理解 Lambda 表達式的語法結構

回到剛纔尋找最長單詞的要求,前面使用的函數式 API 的語法結構看上去好像很特殊,但其實 maxBy 就是一個普通的函數而已,只不過他接收的是一個 Lambda 類型的參數,並且在遍歷集合的時候將每次遍歷的值作爲參數傳給 Lambda 表達式. maxBy 函數的工作原理是根據我們傳入的條件來遍歷集合,從而找到該條件下的最大值,所以說剛好符合我們查找最大長度的單詞的需求

現在來演示一下推倒過程

根據以上的工作原理可得:

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    val lambda = { name: String -> name.length }
    val maxLength = list.maxBy(lambda)
    print("max is $maxLength")
}

可以看到 maxBy 函數實質上就是接收了一個 Lambda 函數而已,並且這個 Lambda 函數完全可以按照剛剛說的表達式的語法結構來定義

這種寫法雖然可以工作,但是比較囉嗦,可簡化的點也很多

首先,我們不需要專門定義一個lambda變量,而是可以將lambda表達式直接傳入函數當中:

val maxLength = list.maxBy({ name: String -> name.length })

Kotlin規定,當Lambda參數是函數的最後一個參數時,可以將 Lambda 表達式移動到函數的括號外面:

val maxLength = list.maxBy() { name: String -> name.length }

如果 Lambda 參數是函數唯一的參數的話,還可以將函數的括號省略:

val maxLength = list.maxBy { name: String -> name.length }

由於 Kotlin 擁有出色的類型推到極致, Lambda 表達式中的參數在大多數情況下不必聲明參數類型:

val maxLength = list.maxBy { name -> name.length }

當 Lambda 表達式的參數列表中只有陽光參數時,也不用聲明參數名,可以使用 it 關鍵字來代替:

val maxLength = list.maxBy { it.length }

這就是最初的我們的那種寫法

幾個集合中比較常用的函數式 API

map

集合中的 map 函數是最常用的一種函數式 API ,他用於將集合中的每個元素都映射成一個另外的值,映射的規則在 Lambda 表達式中指定,最終生成一個新的集合. 比如我們把所有的名稱都變成大寫:

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    val maxLength = list.map { it.toUpperCase() }
    for (name in maxLength) {
        println(name)
    }
}

map 的功能非常強大,他可以按照我們的需求對集合中的元素進行任意的映射轉換,只需要在 Lambda 中編寫你需要的邏輯即可

filter

filter 函數是用來過濾集合中的數據都,他可以單獨使用,也可以配合剛纔的 map 函數一起使用

比如我們只保留兩個字母以內的,就可以藉助 filter 來實現

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    val maxLength = list.filter { it.length < 3 }.map { it.toUpperCase() }
    for (name in maxLength) {
        println(name)
    }
}

需要注意調用順序來提高效率

any和all

any 用於判斷集合中是否至少存在一個元素滿足指定條件

all 用於判斷集合中是否所有的元素都滿足指定條件

fun main() {
    val list = listOf("a", "ab", "abc", "bc")
    val anyResult = list.any { it.length <= 3 }
    val allResult = list.all { it.length <= 3 }

    println("anyResult is $anyResult, allResult is $allResult")
}

微信掃描二維碼,關注我的公衆號
歡迎關注這個不是技術號的公衆號,我們聊聊別的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章