3.3 集合、序列和Java中的流

3.3.1 集合中的函数式API

虽然Kotlin集合中的函数式API类似于Java 8 Stream中的API,但是Kotlin的集合跟Java的集合并不一致。

Kotlin的集合分为可变集合(Mutable Collection)和不可变集合(Immutable Collection)。不可变集合是List、Set、Map,它们是只读类型的,不能对集合进行修改。可变集合是MutableList、MutableSet、MutableMap,它们是支持读写的类型,能够对集合进行修改。

Kotlin集合中的函数式API跟大部分支持Lambda语言的函数式API类似。下面仅以filter、map、flatMap三个函数为例演示使用集合的高阶函数。

1.filter的使用

过滤集合中大于10的数字,并把它们打印出来。

执行结果如下:

     12
     33

::println是方法引用(Method Reference),它是简化的Lambda表达式。

上述代码等价于下面的代码:

2.map的使用

将集合中的字符串都转换成大写,并打印出来。

执行结果如下:

     JAVA
     KOTLIN
     SCALA
     GROOVY

3.flatMap的使用

遍历所有的元素,为每一个创建一个集合,最后把所有的集合放在一个集合中。

执行结果如下:

     [5, 6, 12, 13, 8, 9, 33, 34]
     3.3.2  Sequence

序列(Sequence)是Kotlin标准库提供的另一种容器类型。序列与集合有相同的函数API,却采用不同的实现方式。

其实,Kotlin的Sequence更类似于Java 8的Stream,二者都是延迟执行的。Kotlin的集合转换成Sequence只需使用asSequence()方法。

或者使用sequenceOf()直接创建新的Sequence:

在Kotlin 1.2.70的Release Note上曾说明:使用Sequence有助于避免不必要的临时分配开销,并且可以显著提高复杂处理PipeLines的性能。

下面编写一个例子来证实这个说法:

通过基准测试得到如下结果:

上述例子使用OpenJDK提供的基准测试工具JMH进行测试,可以在方法层面进行基准测试。上述例子的结果表明,在多次链式调用时,Sequence比起List具有更高的效率。

这是因为集合在处理每个步骤时都会返回一个新集合,序列不会在每个处理步骤中创建集合。对于数据量比较大时,应该选择序列。