前言
最近在学习kotlin的时候,发现了一个 骚操作 ,它叫集合的惰性操作。什么,你问我为什么称它 骚 ?我也不知道,反正脑海中就浮现了这么个词语!可能是贫穷限制了我的想象力!
举个栗子
比如有这么一个场景,你是一家猎头公司的人员(别问我为什么是猎头,因为我看完猎场了)。然后你需要从一批人员中筛选符合条件的人选。1
2
3
4
5
6data class Person(var name: String, var age: Int = 0, var workYear: Int = 0, var mail: String?)
val persons = listOf(Person("Tom", 20, 2, "Tom@mail.com"),
Person("Mike", 22, 3, "Mike@mail.com"),
Person("Jerry", 21, 3, "Jerry@mail.com"),
Person("Atom", 22, 2, "Atom@mail.com"))
你需要筛选出工作年限不小于3年的人的联系方式,然后联系他们准备进行面试。1
2
3
4
5
6
7println(persons.filter {
println("filter operate!")
it.workYear >= 3
}.map {
println("map operate!")
it.mail
})
上面的代码会输出如下的结果,这样你就成功的筛选出了Mike和Jerry。 如果你不了解 filter 和 map 两个扩展函数,可以查看源码中的这两个扩展函数是怎么写的 _Collections.kt。从输出结果上我们也可以看出它的流程是这样的,先对persons集合的每一个元素调用filter,然后会产生一个新的集合,然后对新的集合调用map,这样就得到了所有符合条件人员的联系方式。
Sequence序列
上面已经说明了这段代码的执行流程,倘若你要从你们成百上千万的人才库中筛选这些人员,执行效率是不是就非常低下了,而且如果变换操作过多的时候,你会创建很多个临时的集合。这时候,惰性操作就出来的,解释排后,代码先行!1
2
3
4
5
6
7
8
9
10println("result is:" + persons.asSequence()
.filter {
println("filter operate!")
it.workYear >= 3
}
.map {
println("map operate!")
it.mail
}
.toList())
上面这段代码输出结果是这样的。 我们很容易就能够看出,它会对persons中的每一个元素先调用filter,如果满足条件再调用map;它是一个元素操作完之后再对另外一个元素做操作。我们再来看看一个神奇的现象,先把toList()删除掉,它会输出这个结果。 很神奇吧,它没有对persons中的元素做任何操作,只是单纯的返回了一个TransformingSequence的对象。
序列的操作
我们可以将序列的操作分为两类,intermediate operation 和 terminal operation 。看下面这张图你就明白了。 intermediate operation是惰性的。从上面的代码我们可以看出,只有当terminal operation执行的时候,intermediate operation才会执行。
总结
- 序列是对集合的每一个元素做所有的操作,而没有使用序列的时候是对一个集合做完某个操作后再对新的集合做后续操作;
- 序列只有在terminal operation调用的时候才会执行所有的操作。