Kotlin序列Sequence

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

Kotlin序列Sequence

Kotlin序列Sequence

序列(Sequence):

首先我们来了解一下什么是序列,序列其实类似集合的一个接口,只不过它的操作都是惰性集合操作,所有在集合上的操作符都适用于序列。下面我们来看看如何生成一个序列:


1
// 列表和序列
2val list = listOf(1,2,3,4)
3println(list)
4println(list.asSequence())
5
6输出:
7[1234]
8   kotlin.collections.CollectionsKt___CollectionsKt$asSequence$$inlined$Sequence$1@13fee20c

生成一个序列的一种方式就是通过list.asSequence(),但是我么在输出日志中才发现它的输出其实没有内容,那么如果要查看序列的内容可以将它转换为集合。


1
println(list.asSequence().toList())
2
3输出:
4[1, 2, 3, 4]

这样我们接可以看到结果。


序列的优势:

那么有了集合这么好用的东西,我们为什么要使用序列呢?接下来我们看一个小小的例子:
我们拿到了100W条用户数据,需要将这些用户年龄是偶数的姓名全打印出来。如果不使用序列,我们的做法为:


1
println(userList
2        .filter { it.age % 2 != 0 }
3        .map { User::age })

这个写法肯定没有错,对于少量数据来说也没什么影响,可是这里大家注意,是100W条数据,我们可以点击mapfilter查看源码,每一步操作都会生成另外一个集合,对于大量数据来说,这可是一笔很大的消耗,在性能上是很不理想的。这时候就到了我们序列大显身手的时候了,来看看序列是如何减少性能消耗的:


1
println(userList.asSequence()
2        .filter { it.age % 2 != 0 }
3        .map { User::age }
4        .toList())

这里我们先将集合转换为序列,在最后的操作中才将序列转换为集合的。序列在中间操作都是惰性的,不会创建额外的集合来保存过程中产生的中间结果,使用序列可以高效的对集合元素执行链式操作。


序列操作的执行过程:

Kotlin序列Sequence
序列操作.png

序列操作分为两个过程:中间操作、末端操作。中间操作全部都是惰性操作,如果没有执行末端操作,中间操作都会被延期。我们来看以下代码加深理解:


1
val list = listOf(1234)
2list.asSequence().filter { print(it);it > 2 }
3list.asSequence().filter { print(it);it > 2 }.toList()

我们在中间操作filter()打印集合的元素,但是在日志中会发现,不加toList()的是不会有任何结果的,只有加上了toList()才会执行print(it)操作,也就证明了为什么说中间操作是惰性的,在没有末端操作的时候,中间操作会被延期。

注意:末端操作的定义可以理解为:只要不是在这个操作后生成的对象依旧是序列就属于末端操作。


序列和集合的执行顺序:

对于一个链式操作,我们可以先大致猜一下,序列和集合的执行顺序是否是一样?
我们来通过一个简单的例子理解下:


1
    val list = listOf(1, 2, 3, 4)
2    list.map { print("map($it) "); it * it }
3            .filter { print("filter($it )"); it > 5 }
4    println()
5    list.asSequence()
6            .map { print("map($it) ");it * it }
7            .filter { print("filter($it) ");it > 5 }
8            .toList()

这个例子很简单,map之后filter,每一步操作我们都做输出处理,结果如下:


1
map(1map(2map(3map(4) filter(1 )filter(4 )filter(9 )filter(16 )
2map(1) filter(1map(2) filter(4map(3) filter(9map(4) filter(16)

从结果我们一眼就能看出,集合和序列在链式的执行顺序是不一样的,集合在链式中先处理完第一步所有的元素,再处理第二步所有的元素,以此类推。而序列不是,序列是对每个元素做链式操作,只有第一个元素执行完所有的链式操作,才执行第二个元素的链式操作。

千万不要小瞧这个区别,它将为我们在大量数据处理上带来很大的优化和便捷。比如:


1
    val list = listOf(1234,·······)
2    list.map { it * it }
3            .find { it > 5 }
4    list.asSequence()
5            .map { it * it }
6            .find { it > 5 }

这里我们想象集合中有大量的数据,集合和序列的执行流程如下:

Kotlin序列Sequence
序列和集合的执行顺序.png


从图中我们可以得出这样一个结论,在map()中间操作的时候,集合需要将每一个元素都执行一次,但是序列在找到满足find { it > 5 }的元素时,map()操作将不会继续执行,可以减少不需要的大量操作。这就是序列的另一大优势。



总结:

无论是在集合还是序列的链式操作中,都需要大量的使用到Lambda,熟练的使用Lambda结合集合和序列的转换将在日常开发中得到一种很完美的编码体验,希望大家一定要熟悉的理解序列和集合之间联系和区别。


写在最后

每个人不是天生就强大,你若不努力,如何证明自己,加油!

Thank You!

--Taonce

如果你觉得这篇文章对你有所帮助,那么就动动小手指,长按下方的二维码,关注一波吧~~

Kotlin序列Sequence
专注Kotlin的公众号



原文始发于微信公众号(Taonce):Kotlin序列Sequence