Stream组成
在传统Java编程,或者说是类C语言编程中,我们如何操作一个数组数据呢?或者更泛化的讲,我们如何操作一个“集合”(Collection)数据呢?在Java中我们利用java.util包里的各种数据结构封装,来很好的表示了数组(Array)、集合(Set)、列表(List)和kv对象(Map)。但是抽象表示只是意味着存储和定义操作方法,具体如何访问中间的数据,其实还是比较原始的,或者换句话说,操作一个Collection的数据,我们使用的是Collection本身提供的API。就如我们访问一个List里的所有数据,需要一个for循环来get每个element。
Java 8引入了一个Stream对象,来重新封装集合中的数据,就像集合根据其特定的数据结构存储了数据,而Stream将其表示为一个数据流,一个类似List的有序的数据流。值得一提的是,Stream是不存储数据的,它核心是要将不同的数据——流化。
Stream包含一个*数据源头*(Source),一组(0个或多个)*中间操作*和一个*终止操作*。其实很好理解,一个流一定需要一个数据*源头*,毕竟要确定是哪些数据要流式处理。*中间操作*是一些类似map、filter之类的转换操作,也就是说map和filter只是将一个流变为新的流,它们可以串起来(stream pipeline)。而*终止操作*顾名思义,*终止操作*会结束流,*终止操作*包括产出结果型和边际效果型(side-effect),其中前者比如count之类的产出一个int值的,后者则是forEach之类的允许后续处理的。下面具体分开讲解一下Stream的各个组成部分。
源头(Source)
其中源头来源于数组、Collection、I/O资源和生成函数。
Arrays
通过一个数组生成一个流,是比较容易理解的。Java API也是通过Arrays.stream()方法来实现的:
public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
}
看其声明就是将一个数组转换为一个Stream对象。其委托StreamSupport来构造,而StreamSupport的stream方法声明如下:
public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
Objects.requireNonNull(spliterator);
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}
这里一个很重要的参数是Spliterator,这是构造流的核心。ReferencePipeline.Head构造方法就是将一些属性设置好。而ReferencePipeline是个重要的概念,它是pipeline里对于*中间操作*和*源头*实现的抽象类,从其类声明中可以看出:
abstract class ReferencePipeline<P_IN, P_OUT>
extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
implements Stream<P_OUT> {
}
两个泛型表示了pipeline的输入和输出。*中间操作*的实现很多也是由其实现的,比如map和filter。回到刚才的分析,因为ReferencePipeline构造后没有后续的方法链调用了。所以要理解的就是Spliterator这个东西是什么。
阅读全文直接点击:http://click.aliyun.com/m/9890/