Kotlin入门笔记八:Lambda和序列
![](https://img.haomeiwen.com/i6297937/f21a2adb7b8fb311.jpeg)
- Kotlin入门笔记一:方法、变量、类
- Kotlin入门笔记二:when、for、in
- Kotlin入门笔记三:可空类型
- Kotlin入门笔记四:集合
- Kotlin入门笔记五:可见修饰符
- Kotlin入门笔记六:Lambda语法
- Kotlin入门笔记七:Lambda之引用
- Kotlin入门笔记八:Lambda和序列
序列(Sequence):
首先我们来了解一下什么是序列,序列其实类似集合的一个接口,只不过它的操作都是惰性集合操作,所有在集合上的操作符都适用于序列。下面我们来看看如何生成一个序列:
// 列表和序列
val list = listOf(1,2,3,4)
println(list)
println(list.asSequence())
输出:
[1, 2, 3, 4]
kotlin.collections.CollectionsKt___CollectionsKt$asSequence$$inlined$Sequence$1@13fee20c
生成一个序列的一种方式就是通过list.asSequence()
,但是我么在输出日志中才发现它的输出其实没有内容,那么如果要查看序列的内容可以将它转换为集合。
println(list.asSequence().toList())
输出:
[1, 2, 3, 4]
这样我们接可以看到结果。
序列的优势:
那么有了集合这么好用的东西,我们为什么要使用序列呢?接下来我们看一个小小的例子:
我们拿到了100W条用户数据,需要将这些用户年龄是偶数的姓名全打印出来。如果不使用序列,我们的做法为:
println(userList
.filter { it.age % 2 != 0 }
.map { User::age })
这个写法肯定没有错,对于少量数据来说也没什么影响,可是这里大家注意,是100W条数据,我们可以点击map
和filter
查看源码,每一步操作都会生成另外一个集合,对于大量数据来说,这可是一笔很大的消耗,在性能上是很不理想的。这时候就到了我们序列大显身手的时候了,来看看序列是如何减少性能消耗的:
println(userList.asSequence()
.filter { it.age % 2 != 0 }
.map { User::age }
.toList())
这里我们先将集合转换为序列,在最后的操作中才将序列转换为集合的。序列在中间操作都是惰性的,不会创建额外的集合来保存过程中产生的中间结果,使用序列可以高效的对集合元素执行链式操作。
序列操作的执行过程:
![](https://img.haomeiwen.com/i6297937/cad7912d96da8b05.png)
序列操作分为两个过程:中间操作、末端操作。中间操作全部都是惰性操作,如果没有执行末端操作,中间操作都会被延期。我们来看以下代码加深理解:
val list = listOf(1, 2, 3, 4)
list.asSequence().filter { print(it);it > 2 }
list.asSequence().filter { print(it);it > 2 }.toList()
我们在中间操作filter()
打印集合的元素,但是在日志中会发现,不加toList()
的是不会有任何结果的,只有加上了toList()
才会执行print(it)
操作,也就证明了为什么说中间操作是惰性的,在没有末端操作的时候,中间操作会被延期。
注意:末端操作的定义可以理解为:只要不是在这个操作后生成的对象依旧是序列就属于末端操作。
序列和集合的执行顺序:
对于一个链式操作,我们可以先大致猜一下,序列和集合的执行顺序是否是一样?
我们来通过一个简单的例子理解下:
val list = listOf(1, 2, 3, 4)
list.map { print("map($it) "); it * it }
.filter { print("filter($it )"); it > 5 }
println()
list.asSequence()
.map { print("map($it) ");it * it }
.filter { print("filter($it) ");it > 5 }
.toList()
这个例子很简单,map
之后filter
,每一步操作我们都做输出处理,结果如下:
map(1) map(2) map(3) map(4) filter(1 )filter(4 )filter(9 )filter(16 )
map(1) filter(1) map(2) filter(4) map(3) filter(9) map(4) filter(16)
从结果我们一眼就能看出,集合和序列在链式的执行顺序是不一样的,集合在链式中先处理完第一步所有的元素,再处理第二步所有的元素,以此类推。而序列不是,序列是对每个元素做链式操作,只有第一个元素执行完所有的链式操作,才执行第二个元素的链式操作。
千万不要小瞧这个区别,它将为我们在大量数据处理上带来很大的优化和便捷。比如:
val list = listOf(1, 2, 3, 4,·······)
list.map { it * it }
.find { it > 5 }
list.asSequence()
.map { it * it }
.find { it > 5 }
这里我们想象集合中有大量的数据,集合和序列的执行流程如下:
![](https://img.haomeiwen.com/i6297937/4612a7e1e6a178ca.png)
从图中我们可以得出这样一个结论,在
map()
中间操作的时候,集合需要将每一个元素都执行一次,但是序列在找到满足find { it > 5 }
的元素时,map()
操作将不会继续执行,可以减少不需要的大量操作。这就是序列的另一大优势。
总结:
无论是在集合还是序列的链式操作中,都需要大量的使用到Lambda,熟练的使用Lambda结合集合和序列的转换将在日常开发中得到一种很完美的编码体验,希望大家一定要熟悉的理解序列和集合之间联系和区别。
下一份笔记将为大家带来Kotlin版的MVP+OKhttp3+Retrofit+RxJava的项目基本框架
写在最后
每个人不是天生就强大,你若不努力,如何证明自己,加油!
Thank You!
--Taonce