安卓語言基礎之Kotlin高階函數——Lambda表達式(一)

語言: CN / TW / HK

theme: condensed-night-purple

本文正在參加「金石計劃 . 瓜分6萬現金大獎」

前言

前段時間在技術交流羣裏看一羣大佬在説Kotlin的高階函數,看起來花裏胡哨,對我這個以Java語言為生產工具的安卓開發十分不友好,但是為了能以後和他們一起更好的水羣,我開始學習高階函數,去了解它的魅力。

我將本篇歸屬於安卓開發基礎必備系列,因為這部分知識屬於開發語言基礎知識,此外,高階函數也是很多人推崇Kotlin的魅力所在。

正篇

首先我們看看Lambda編程,這個編程方式還是我在用Java開發安卓時候用點擊事件時被Warnings提醒知曉的,AS推薦將匿名函數換為Lambda方式,再後面的學習中瞭解到這是一種語法糖。

Lambda是計算機編程語言,Lambda表達式是一個匿名函數,它可以包含表達式和語句,並且可用於創建委託或表達式目錄樹類型。

語法糖(Syntactic sugar),也譯為糖衣語法,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用。通常來説使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會。

Warning提醒我推薦替換成Lambda表達式:

image.png ```Java vHello.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {

}

}); 替換為:Java vHello.setOnClickListener(v -> {

}); ``` 以上是Lambda表達式的一個例子,下面我們來詳細看看這種編程方式:

集合的函數式API

我們通常去尋集合種元素長度最長的寫法如下Demo: Kotlin val list = listOf("Apple", "Banana", "Pear") var maxLengthFruit = "" for (fruit in list) { if (fruit.length > maxLengthFruit.length) { maxLengthFruit = fruit } } println("max length fruit is $maxLengthFruit") 而如果我們使用集合的函數式API就非常簡潔: Kotlin val list = listOf("Apple", "Banana", "Pear") val maxLengthFruit = list.maxBy { it.length } println("max length fruit is $maxLengthFruit") 一段for循環直接簡化為一句,但對於不熟悉這種表達方法的就會一頭霧水,最早我接觸的時候就感覺不利於閲讀,其實學完後就感覺這種寫法還是很爽的,接下來,為了看懂這種寫法,我們先了解一下Lambda,它就是一小段可以作為參數傳遞的代碼,通常情況下我們編程都是向某個函數傳參時傳入變量,但Lambda可以做到傳入一小段代碼,而且其實這一小段的定義中未規定長短(通常不建議在Lambda表達式編寫過長的代碼,防止影響代碼可讀性)。

Lambda表達式的語法結構如下:

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

我們可以看到,最外層是大括號,然後內部首先聲明瞭參數列表,然後用“->”符號連接結尾的函數體,表示參數列表結束和函數體開始,函數體可以編寫我們想實現的邏輯代碼(不建議過長),最後位於最後一行的代碼會自動作為Lambda表達式的返回值。

當然這是完整的寫法,此外還有更為簡化的版本,不過首先我們需要先了解Lambda的完整表達式,方便向更深層學習。

瞭解了完整的表達式,我們來一步步看如何簡化到之前的代碼的:

maxBy其實是一個普通的函數,它可以接受一個Lambda類型的參數,並會遍歷集合時每次遍歷的值作為參數傳遞給Lambda表達式,也就是可以根據我們傳入的條件來遍歷集合,然後找到該條件下的最大值。

知曉了maxBy函數,那麼首先,我們可以根據完整表達式寫出如下代碼: Kotlin val list = listOf("Apple", "Banana", "Pear") val lambda = { fruit: String -> fruit.length} val maxLengthFruit = list.maxBy(lambda) println("max length fruit is $maxLengthFruit") 我們將Lambda表達式作為參數傳入了maxBy函數中,但其實是可以去簡化該寫法的,因為我們不需要專門去定義一個lambda變量,直接將其視為參數傳入該函數中: Kotlin val list = listOf("Apple", "Banana", "Pear") val maxLengthFruit = list.maxBy({ fruit: String -> fruit.length}) println("max length fruit is $maxLengthFruit") 此時,編譯器會報Warning:

image.png 這告訴我們當Lambda參數是函數的唯一一個參數時,可以將函數的括號省略: Kotlin val list = listOf("Apple", "Banana", "Pear") val maxLengthFruit = list.maxBy { fruit: String -> fruit.length } println("max length fruit is $maxLengthFruit") 由於Kotlin有類型推導機制,所以我們的Lambda表達式的參數列表在大多數情況下其實不用聲明參數類型,於是我們進一步將其簡化: Kotlin val maxLengthFruit = list.maxBy { fruit -> fruit.length } 而Lambda表達式在參數列表中只有一個參數時甚至不用聲明參數名,即可用it關鍵字來代替,於是最終變成我們最初看到的那個最簡代碼: Kotlin val maxLengthFruit = list.maxBy { it.length }

其他常用的集合函數式API

除了maxBy函數API以外,還有好幾個很好用的集合函數式API,比如:

map函數

這個函數用於將集合的每個元素都映射成另外的值,映射規則在Lambda表達式中指定,然後生成一個新的集合,如下Demo: Kotlin val list = listOf("Apple", "Banana", "Pear") val newList = list.map { it.uppercase(Locale.getDefault()) } for (fruit in newList) { println(fruit) } 上述代碼將list的元素全部變為大寫,然後生成新的列表。

filter函數

這個函數可以用來過濾集合的一些數據,可以單獨使用也能結合map函數一起使用,如下demo: Kotlin val newList = list.filter { it.length <= 5 } .map { it.uppercase(Locale.getDefault()) } 上面代碼可以將生成的新列表元素長度控制在5個字符以內。

any與all函數

any函數可以用於判斷集合中是否至少存在一個元素滿足指定條件,而all函數則用於判斷集合中是否所有元素都滿足指定條件,如下demo: val anyResult = list.any { it.length <= 5 } val allResult = list.all { it.length <= 5 } println("anyResult is $anyResult, allResult is $allResult") 上面代碼條件設置為元素長度是否在5個字符以內,allResult要所有元素滿足該條件才能true,而anyResult只要有一個元素滿足條件即返回true。

總結

本篇主要是講述了Lambda編程中集合的函數式API用法,是Kotlin高階函數的前置第一篇,下一篇我們看看Lambda編程的Java函數式API的用法,其實就是開篇説到的點擊事件的那種類型,然後我們再去探究Kotlin中的高階函數如何去寫。