Kotlin: Lambda表达式语法糖

Java从JDK1.8之后开始加入了Lambda编程的语法支持.而Kotlin从第一个版本就开始支持.

本文将通过集合的函数式API来学习Lambda编程.

现在我们有一个需求,创建一个包含许多水果名称的集合.

如果是在Java中,你会怎么做呢?可能你首先会创建一个ArrayList的实例,然后将说过的名称一个个添加到集合中.当然,在Kotlin中也可以这么做.

val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("Orange")
list.add("Pear")
list.add("Grape")
list.add("Watermelon")

在Kotlin中,有一种更简洁的表达方式,如下:

 val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")

现在有一个新的需求,找出上述水果集合中,单词最长的那个水果?这个需求也比较简单.
代码如下:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")

var maxLengthFruit = ""

for (fruit in list) {
    
    
   if (fruit.length > maxLengthFruit.length) {
    
    
       maxLengthFruit = fruit
   }
}

Log.d("最长单词的水果是:", maxLengthFruit)

如果我们使用Koltin中集合的函数式API,这个功能可以更加简单:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy {
    
     it.length }
Log.d("最长单词的水果是:", maxLengthFruit)

上述代码使用的就是函数式API的用法,只用一行代码就能找到集合中单词最长的那个水果.

现在我们通过这一行代码,来学习Kotlin表达式的语法结构。

首先来看一下Lambda的定义,如果用最直白的语言来阐述,Lambda就是一小段可以作为参数传递的代码。从定义上看,这个功能就很厉害了,因为正常情况下,我们向某个函数传参数时只能传入变量,而借助Lamada却运行传入一小段代码。至于多少才算“一小段代码”,Kotlin没有进行限制。但是通常不建议在Lambda表达中编写太长的代码,否则可能会影响代码的可读性。

接着我们来看一下Lambda表达式的语法结构:

{ 参数名1:参数类型,参数名2:参数类型 ->函数体 }

这是Lambda表达式最完整的语法结构定义.首先最外层是一对大括号,如果有参数传入到Lambda表达式中的话,我们还需要声明参数列表, 参数列表的结尾使用一个 -> 符合,表示参数列表中的结束以及函数体的开始,函数体中可以编写任意行代码,并且最后一行代码会自动作为Lambda表达式的返回值.

当然,在很多情况下,我们并不需要使用Lambda表达式完整的语法结构,而是又很多种简化的写法.但是简化版的写法对于初学者而言更难理解,因此这里我准备使用一步步推到演化的方式,向你展示这些简化版的写法是从何而来的,这样你就能对Lambda表达式的语法结构理解得更加彻底了.

回到刚刚的找到最长单词的需求,前面使用的函数式API的语法结构看起来好像很特殊,但其实maxBy就是一个普通的函数而已,只不过它接收的是一个Lambda类型的参数,并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式.maxBy函数的工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值,比如我们说想要找到单词最长的水果,那么条件自然就是单词的长度了.

理解了maxBy函数的工作原理之后,我们就可以套用刚才学习的Lambda表达式的语法结构,并将它传入到maxBy函数中,如下所示:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val lambda = {
    
     fruit: String -> fruit.length }
Log.d("最长单词的水果是:", list.maxBy(lambda))

可以看到,maxBy函数实质上就是收到了一个Lambda参数而已,并且这个Lambda参数是完全按照刚才学的表达式的语法结构来定义的,因此这段代码应该算是比较好懂的.

这种写法虽然可以正常工作,但是比较啰嗦,可简化的点也比较多,下面我们就开始对这段代码进行一步步简化.

首先,我们不需要专门定义一个Lamada变量,而是可以直接将lambda表达式移到maxBy函数当中,因此第一步简化如下所示:

 val maxLenghtFruit = list.maxBy({
    
     fruit: String -> fruit.length })

然后Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面,如下所示:

 val maxLenghtFruit = list.maxBy() {
    
     fruit: String -> fruit.length }

接下来,如果Lambda参数时函数的唯一一个参数时,还可以将函数的括号省略:

val maxLenghtFruit = list.maxBy {
    
     fruit: String -> fruit.length }

这样代码看上去就变得清爽了很多.但是我们还可以继续简化.由于Kotlin拥有出色的类型推导机制,Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型,因此代码可以进一步简化成:

val maxLenghtFruit = list.maxBy {
    
     fruit -> fruit.length }

最后,当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来替代,那么代码就变成了:

val maxLenghtFruit = list.maxBy {
    
     it.length }

通过一步步的推导,我们就得到了与 最开始那段函数式API 一模一样的写法.

以上,就是Lambda表达式语法糖的内容.

猜你喜欢

转载自blog.csdn.net/gaolh89/article/details/105986914