1. Lambda编程
1.1
集合的函数式API但是入门 Lambda编程 的最佳示例,
这里我们先创建一个水果集合,并且向里面添加水果:
// 第一种方式
val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("watermelon")
list.add("Pear")
这种初始化集合的方式比较繁琐, Kotlin专门提供了一个内置的listOf()
函数来简化初始化集合的操作:
val list = listOf("Apple", "Banana", "watermelon", "Pear")
遍历集合的操作 for-in 循环:
fun main() {
// val list = ArrayList<String>()
// list.add("Apple")
// list.add("Banana")
// list.add("watermelon")
// list.add("Pear")
val list = listOf("Apple", "Banana", "watermelon", "Pear")
for (fruit in list) {
println(fruit)
}
}
运行结果:
需要注意的是 listof函数创建的集合是一个不可变的集合
那么如何创建一个可变的集合呢?
val list = mutableListOf("Apple", "Banana", "watermelon", "Pear")
list.add("Grape")
前面介绍的都是用List集合的用法,实际上Set集合的用法几乎与它一样,
只是将创建集合的方式换成了setOf()和mutableSetOF()函数而已.
val set = setOf("Apple", "Banana", "watermelon", "Pear")
for (fruit in set) {
println(fruit)
}
需要注意的是 Set集合底层使用的是hash映射机制来存放数据的,
因此集合中的元素无法保证有序, 这是和List集合最大的不同之处.
我们来看一下Map集合.
Map是一种键值对型的数据结构,因此在用法上和List,Set集合有着较大的不同.
这是传统的写法:
val map=HashMap<String,Int>()
map.put("Apple",1)
map.put("Banana",2)
map.put("watermelon",3)
map.put("Pear",4)
map.put("Grape",5)
Kotlin更推荐这种写法:
val map=HashMap<String,Int>()
map["Apple"] = 1
map["Banana"] = 2
map["watermelon"] = 3
map["Pear"] = 4
map["Grape"] = 5
从map中读取一条数据可以这么写:
val number=map["Apple"]
Kotlin提供了mapOf()和mutableMapOf()函数来继续简化Map的用法.
在mapOf()函数中,我们可以直接传入初始化的键值对组合来完成对Map集合的创建.
val map = mapOf("Apple" to 1, "Banana" to 2, "watermelon" to 3, "Pear" to 4)
这里的to并不是关键字, 而是infix函数
遍历Map集合:
fun main() {
val map = mapOf("Apple" to 1, "Banana" to 2, "watermelon" to 3, "Pear" to 4)
for ((fruit, number) in map) {
println("fruit is $fruit , number is $number")
}
}
关于集合的创建和遍历就学到这里了, 下面开始学习集合的函数式API,
从而正式入门Lambda编程.
首先我们先来考虑一个需求,如何在一个水果集合里面找到单词最长的那个水果?
当然这个需求很简单, 也有很多种写法, 你可能会很自然的这样写出来:
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var maxLengthFruit = ""
for (fruit in list) {
if (fruit.length > maxLengthFruit.length) {
maxLengthFruit = fruit
}
println(maxLengthFruit)
}
}
虽然这段代码很简洁, 思路也很清晰, 但如果我们使用集合的函数式API,
就可以让这个功能变得更加容易
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit=list.maxBy { it.length }
println("maxLengthFruit is $maxLengthFruit.")
}
或许你现在看来比较吃力, 但当你学完Lambda表达式的语法后,
再回头来看这段代码, 你就会觉得非常简单了.
1.2 Lambda定义:
如果用最直白的话来阐述.lambda就是一小段可以作为参数传递的代码.
从定义看, 正常情况下, 我们向某个函数传入参数时只能传入变量,
但借助Lambda却允许传入一小段代码.
注意: 这里的一小段代码并没有现在多长,
但是不建议在Lambda表达式中写入大量的代码, 否则会极大的影响代码的可读性.
Lambda表达式的语法结构:
{参数名1 : 参数类型 , 参数名2 : 参数类型 -> 函数体}
函数体中可以编写任意行代码,
并且最后一行代码会作为Lambda表达式的返回值.
maxBy()函数的工作原理是根据我们传入的条件来遍历集合,
从而找到该条件下的最大值.
理解了maxBy()函数的工作原理后,我们开始套用Lambda表达式
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy(lambda)
可以看maxBy()函数实际上是接收了一个Lambda参数而已.
下面开始简化代码:
一.我们不需要专门定义lambda变量,而是直接将lambda传入到maxBy()函数中
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy({ fruit: String -> fruit.length })
二.Kotlin规定, 当Lambda表达式是函数的最后一个参数时,可以将它写在外面
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy(){ fruit: String -> fruit.length }
三.如果Lambda表达式是唯一参数,则可以省略()
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy{ fruit: String -> fruit.length }
四.由于Kotlin拥有出色的类型推导机制,
所有在大多数情况下可以省略参数的类型
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy { fruit -> fruit.length }
五.当Lambda表达式的参数列表只有一个参数时,
也不必声明参数名,而是可以使用it关键字来代替
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit=list.maxBy { it.length }
所以这里就得到了最开始的Lambda表达式的形式.
接下来我们再来学习几个集合中常用的API,
相信这些对于现在的你来说,已经没有什么难度了.
集合中的map函数是最常用的一种函数式的API,
它用于将集合中的每个元素都映射成为一个另外的值,
映射的规则是在Lambda表达式中指定,最终生成一个新的集合.
比如现在我们希望让所有的水果名都变为大写的字母.
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val newList=list.map { it.toUpperCase() }
for (fruit in newList){
println(fruit)
}
}
运行结果:
接下来我们学习另外一种比较常用的函数式API-filter函数.
顾名思义,filter函数就是过滤集合里的数据用的,它可以单独使用,
也可以结合map使用.比如我们向只保留5个字母以内的水果,我们可以这么做.
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val newList = list.filter { it.length <= 5 }.map { it.toUpperCase() }
for (fruit in newList) {
println(fruit)
}
}
运行结果:
!注意:
上述代码我们是先调用了filter函数再去调用map函数.
如果你是先调用map函数再去调用filter函数,也可以实现相同的效果,
但是效率会低很多.
因为这样相当于要对集合里的所有元素进行一次映射转换后在进行过滤.
接下来我们继续学习2个比较常用的函数式API-any和all函数,
其中any函数用于判断集合中是否至少存在一个满足指定条件的元素,
而all函数则是用于判断集合里所有的元素是否都满足指定的条件.
由于这2个函数比较简单,这里就直接上手代码:
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val anyResult = list.any { it.length <= 5 }
val allResult = list.all { it.length <= 5 }
println("anyResult is $anyResult")
println("allResult is $allResult")
}
运行结果: