Stream API

  1. Java 8集合中的Stream相当于高级版的Iterator
  • Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作
  1. Stream的聚合操作与数据库SQL的聚合操作sorted、filter、map等非常类似
  2. 在数据操作方面,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操作分类

  1. 分为两大类:中间操作(Intermediate operations)和终结操作(Terminal operations)
  2. 中间操作只对操作进行了记录,即只会返回一个流,不会进行计算操作,而终结操作是实现了计算操作
  3. 中间操作又分为无状态(Stateless)操作和有状态(Stateful)操作
  • 无状态操作:元素的处理不受之前元素的影响
  • 有状态操作:该操作只有拿到所有元素之后才能继续下去
  1. 终结操作又分为短路(Short-circuiting)操作与非短路(UnShort-circuiting)操作
  • 短路操作:遇到某些符合条件的元素就可以得到最终结果
  • 非短路操作:必须处理完所有元素才能得到最终结果
  1. 通常会将中间操作称为懒操作,正是因为懒操作结合终结操作,数据源构成的处理管道(Pipeline),实现了Stream的高效



java list stream对实体的bigdecimal字段求和 list的stream的map_API


Stream源码实现


java list stream对实体的bigdecimal字段求和 list的stream的map_内部类_02


  1. BaseStream和Stream为最顶端的接口类
  • BaseStream定义了流的基本接口方法,如spliterator、isParallel等
  • Stream定义了流的常用操作方法,如map、filter等
  1. ReferencePipeline是一个结构类,通过定义内部类组装各种操作流
  • 内部定义了Head、StatelessOp和StatefulOp三个内部类,实现了BaseStream和Stream的接口方法
  1. Sink接口定义每个Stream操作之间关系的协议,包含了begin、end、cancellationRequested、accept方法
  • ReferencePipeline最终会将整个Stream流操作组装成一个调用链
  • 而调用链上的每个Stream操作的上下文关系就是通过Sink接口来定义实现的

Stream操作叠加


java list stream对实体的bigdecimal字段求和 list的stream的map_API_03


  1. 一个Stream的各个操作是由处理管道组装的,并统一完成数据处理
  2. 在JDK中,每次的中断操作都会以使用阶段(Stage)命名
  3. 管道结构通常是由ReferencePipeline类实现的,ReferencePipeline包含Head、StatelessOp、StatefulOp三个内部类
  • Head类主要用来定义数据源操作,初次调用.stream()时,会初次加载Head对象
  • 接着加载中间操作,分为StatelessOp对象和StatefulOp对象
  • 此时的Stage并没有执行,而是通过AbstractPipeline生成了中间操作的Stage链表
  • 当调用终结操作时,会生成一个最终的Stage
  • 通过这个Stage触发之前的中间操作,从最后一个Stage开始,递归产生一个Sink链

样例

List names = Arrays.asList("张三