随笔博文

安卓语言基础之Kotlin高阶函数——Lambda表达式(一)

2022-12-15 12:40:25 michael007js 128

前言

前段时间在技术交流群里看一群大佬在说Kotlin的高阶函数,看起来花里胡哨,对我这个以Java语言为生产工具的安卓开发十分不友好,但是为了能以后和他们一起更好的水群,我开始学习高阶函数,去了解它的魅力。

我将本篇归属于安卓开发基础必备系列,因为这部分知识属于开发语言基础知识,此外,高阶函数也是很多人推崇Kotlin的魅力所在。

# 正篇

首先我们看看Lambda编程,这个编程方式还是我在用Java开发安卓时候用点击事件时被Warnings提醒知晓的,AS推荐将匿名函数换为Lambda方式,再后面的学习中了解到这是一种语法糖。

Lambda是计算机编程语言,Lambda表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

Warning提醒我推荐替换成Lambda表达式:

image.png

vHello.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       
 }
});

替换为:

vHello.setOnClickListener(v -> {

});

以上是Lambda表达式的一个例子,下面我们来详细看看这种编程方式:

集合的函数式API

我们通常去寻集合种元素长度最长的写法如下Demo:

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就非常简洁:

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函数,那么首先,我们可以根据完整表达式写出如下代码:

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变量,直接将其视为参数传入该函数中:

val list = listOf("Apple", "Banana", "Pear")
val maxLengthFruit = list.maxBy({ fruit: String -> fruit.length})
println("max length fruit is $maxLengthFruit")

此时,编译器会报Warning:

image.png这告诉我们当Lambda参数是函数的唯一一个参数时,可以将函数的括号省略:

val list = listOf("Apple", "Banana", "Pear")
val maxLengthFruit = list.maxBy { fruit: String -> fruit.length }
println("max length fruit is $maxLengthFruit")

由于Kotlin有类型推导机制,所以我们的Lambda表达式的参数列表在大多数情况下其实不用声明参数类型,于是我们进一步将其简化:

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

而Lambda表达式在参数列表中只有一个参数时甚至不用声明参数名,即可用it关键字来代替,于是最终变成我们最初看到的那个最简代码:

val maxLengthFruit = list.maxBy { it.length }

其他常用的集合函数式API

除了maxBy函数API以外,还有好几个很好用的集合函数式API,比如:

map函数

这个函数用于将集合的每个元素都映射成另外的值,映射规则在Lambda表达式中指定,然后生成一个新的集合,如下Demo:

val list = listOf("Apple", "Banana", "Pear")
val newList = list.map { it.uppercase(Locale.getDefault()) }
for (fruit in newList) {
   println(fruit)
}

上述代码将list的元素全部变为大写,然后生成新的列表。

filter函数

这个函数可以用来过滤集合的一些数据,可以单独使用也能结合map函数一起使用,如下demo:

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中的高阶函数如何去写。


首页
关于博主
我的博客
搜索