Kotlin集合vs Kotlin序列与Java流

一. 集合中的函数式 API虽然 Kotlin Collection 中的函数式 API 类似于 Java 8 Stream 中的 API 。 但是 Kotlin 的集合跟 Java 的集合并不一致 。
Kolin 的集合分为可变集合(mutable collection)和不可变集合(immutable collection) 。 不可变集合是 List、Set、Map , 它们是只读类型 , 不能对集合进行修改 。 可变集合是 MutableList、MutableSet、MutableMap , 它们是支持读写的类型 , 能够对集合进行修改的操作 。
Kotlin 集合中的函数式 API 跟大部分支持 Lambda 语言的函数式 API 都类似 。 下面仅以 filter、map、flatMap 三个函数为例 , 演示使用集合的高阶函数 。
1.1 filter 的使用过滤集合中大于10的数字 , 并把它打印出来 。
listOf(5, 12, 8, 33)// 创建list集合.filter { it > 10 }.forEach(::println)执行结果:
1233::println 是方法引用(Method Reference) , 它是简化的 Lambda 表达式 。
上述代码等价于下面的代码:
listOf(5, 12, 8, 33).filter { it > 10 }.forEach{ println(it) }1.2 map 的使用将集合中的字符串都转换成大写 , 并打印出来 。
listOf("java","kotlin","scala","groovy").map { it.toUpperCase() }.forEach(::println)执行结果:
JAVAKOTLINSCALAGROOVY1.3 flatMap 的使用遍历所有的元素 , 为每一个创建一个集合 , 最后把所有的集合放在一个集合中 。
val newList = listOf(5, 12, 8, 33).flatMap {listOf(it, it + 1)}println(newList)执行结果:
[5, 6, 12, 13, 8, 9, 33, 34]二. Sequence序列(Sequence)是 Kotlin 标准库提供的另一种容器类型 。 序列与集合有相同的函数 API , 却采用不同的实现方式 。
其实 , Kotlin 的 Sequence 更类似于 Java 8 的 Stream , 二者都是延迟执行 。 Kotlin 的集合转换成 Sequence 只需使用asSequence()方法 。
listOf(5, 12, 8, 33).asSequence().filter { it > 10 }.forEach(::println)亦或者使用sequenceOf()来直接创建新的 Sequence:
sequenceOf(5, 12, 8, 33) // 创建sequence.filter { it>10 }.forEach (::println)在 Kotlin 1.2.70 的 release note 上曾说明:
使用 Sequence 有助于避免不必要的临时分配开销 , 并且可以显着提高复杂处理 PipeLines 的性能 。
下面编写一个例子来证实这个说法:
@BenchmarkMode(Mode.Throughput) // 基准测试的模式 , 采用整体吞吐量的模式@Warmup(iterations = 3) // 预热次数@Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS) // 测试参数 , iterations = 10 表示进行10轮测试@Threads(8) // 每个进程中的测试线程数@Fork(2)// 进行 fork 的次数 , 表示 JMH 会 fork 出两个进程来进行测试@OutputTimeUnit(TimeUnit.MILLISECONDS) // 基准测试结果的时间类型open class SequenceBenchmark {@Benchmarkfun testSequence():Int {return sequenceOf(1,2,3,4,5,6,7,8,9,10).map{ it * 2 }.filter { it % 3== 0 }.map{ it+1 }.sum()}@Benchmarkfun testList():Int {return listOf(1,2,3,4,5,6,7,8,9,10).map{ it * 2 }.filter { it % 3== 0 }.map{ it+1 }.sum()}}fun main() {val options = OptionsBuilder().include(SequenceBenchmark::class.java.simpleName).output("benchmark_sequence.log").build()Runner(options).run()}通过基准测试得到如下的结果:
# Run complete. Total time: 00:05:23REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up onwhy the numbers are the way they are. Use profilers (see -prof, -lprof), design factorialexperiments, perform baseline and negative tests that provide experimental control, make surethe benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.Do not assume the numbers tell you what you want them to tell.BenchmarkModeCntScoreErrorUnitsSequenceBenchmark.testListthrpt2015924.272 ± 305.825ops/msSequenceBenchmark.testSequencethrpt2023099.938 ± 515.524ops/ms


推荐阅读