安卓語言基礎之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中的高階函式如何去寫。