集合的函数式 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 却可以传入一小段代码,那么多长才算一小段代码呢?Kotlin 没有对此进行限制,但通常不建议在 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 }
这就是最初的我们的那种写法
集合中的 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 函数是用来过滤集合中的数据都,他可以单独使用,也可以配合刚才的 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 用于判断集合中是否所有的元素都满足指定条件
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")
}
欢迎关注这个不是技术号的公众号,我们聊聊别的。