Stream API
- Java 8集合中的Stream相当于高级版的Iterator
- Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作
- Stream的聚合操作与数据库SQL的聚合操作sorted、filter、map等非常类似
- 在数据操作方面,Stream不仅可以通过串行的方式实现数据操作,还可以通过并行的方式处理大批量数据,提高处理效率
// java.util.Collectiondefault Stream stream() { return StreamSupport.stream(spliterator(), false);}default Stream parallelStream() { return StreamSupport.stream(spliterator(), true);}
@Dataclass Student { private Integer height; private String sex;}Map> map = Maps.newHashMap();List list = Lists.newArrayList();// 传统的迭代方式for (Student student : list) { if (student.getHeight() > 160) { String sex = student.getSex(); if (!map.containsKey(sex)) { map.put(sex, Lists.newArrayList()); } map.get(sex).add(student); }}// Stream API,串行实现map = list.stream().filter((Student s) -> s.getHeight() > 160).collect(Collectors.groupingBy(Student::getSex));// Stream API,并行实现map = list.parallelStream().filter((Student s) -> s.getHeight() > 160).collect(Collectors.groupingBy(Student::getSex));
优化遍历
Stream操作分类
- 分为两大类:中间操作(Intermediate operations)和终结操作(Terminal operations)
- 中间操作只对操作进行了记录,即只会返回一个流,不会进行计算操作,而终结操作是实现了计算操作
- 中间操作又分为无状态(Stateless)操作和有状态(Stateful)操作
- 无状态操作:元素的处理不受之前元素的影响
- 有状态操作:该操作只有拿到所有元素之后才能继续下去
- 终结操作又分为短路(Short-circuiting)操作与非短路(UnShort-circuiting)操作
- 短路操作:遇到某些符合条件的元素就可以得到最终结果
- 非短路操作:必须处理完所有元素才能得到最终结果
- 通常会将中间操作称为懒操作,正是因为懒操作结合终结操作,数据源构成的处理管道(Pipeline),实现了Stream的高效
Stream源码实现
- BaseStream和Stream为最顶端的接口类
- BaseStream定义了流的基本接口方法,如spliterator、isParallel等
- Stream定义了流的常用操作方法,如map、filter等
- ReferencePipeline是一个结构类,通过定义内部类组装各种操作流
- 内部定义了Head、StatelessOp和StatefulOp三个内部类,实现了BaseStream和Stream的接口方法
- Sink接口定义每个Stream操作之间关系的协议,包含了begin、end、cancellationRequested、accept方法
- ReferencePipeline最终会将整个Stream流操作组装成一个调用链
- 而调用链上的每个Stream操作的上下文关系就是通过Sink接口来定义实现的
Stream操作叠加
- 一个Stream的各个操作是由处理管道组装的,并统一完成数据处理
- 在JDK中,每次的中断操作都会以使用阶段(Stage)命名
- 管道结构通常是由ReferencePipeline类实现的,ReferencePipeline包含Head、StatelessOp、StatefulOp三个内部类
- Head类主要用来定义数据源操作,初次调用.stream()时,会初次加载Head对象
- 接着加载中间操作,分为StatelessOp对象和StatefulOp对象
- 此时的Stage并没有执行,而是通过AbstractPipeline生成了中间操作的Stage链表
- 当调用终结操作时,会生成一个最终的Stage
- 通过这个Stage触发之前的中间操作,从最后一个Stage开始,递归产生一个Sink链
样例
List names = Arrays.asList("张三