Stream流式编程
Java8 中,Collection 新增了两个流方法,分别是 Stream() 和 parallelStream()。
流(Stream)是数据渠道,用于操作数据源所生成的元素序列
集合讲的的是数据,流讲的是计算
特点
- Stream不会存储元素
- Stream不会改变原对象,相反返回一个持有结果的新的Stream
- Stream操作是延迟执行的,这意味着他们会等到需要结果的时候执行
需要使用JUF
实例
找出 偶数ID 年龄大于24 用户名大写 字母名倒序
@Data
@NoArgsConstructor
@AllArgsConstructor
class User{
private Integer id;
private String username;
private int age;
}
public class StreamDemo {
public static void main(String[] args){
User u1 = new User(11,"a",23);
User u2 = new User(12,"b",24);
User u3 = new User(13,"c",22);
User u4 = new User(14,"d",28);
User u5 = new User(16,"e",26);
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
list.stream()
.filter(u -> u.getId() % 2 == 0)
.filter(t -> t.getAge() > 24)
.map(m -> m.getUsername().toUpperCase())
.sorted((o1, o2) -> o2.compareTo(o1))
.forEach(System.out::println);
}
}
Stream操作分类
Stream源码实现
BaseStream 和 Stream 为最顶端的接口类。BaseStream 主要定义了流的基本接口方法,例如,spliterator、isParallel 等;
Stream 则定义了一些流的常用操作方法,例如,map、filter 等。
ReferencePipeline 是一个结构类,他通过定义内部类组装了各种操作流。他定义了 Head、 StatelessOp、StatefulOp 三个内部类,实现了 BaseStream 与 Stream 的接口方法。
Sink 接口是定义每个 Stream 操作之间关系的协议,他包含 begin()、end()、cancellationRequested()、accpt() 四个方法。ReferencePipeline 最终会将整个 Stream 流操作组装成一个调用链,而这条调用链上的各个 Stream 操作的上下关系就是通过 Sink 接口协议来定义实现的。
Stream 操作叠加
我们知道,一个 Stream 的各个操作是由处理管道组装,并统一完成数据处理的。在 JDK 中每次的中断操作会以使用阶段(Stage)命名。
管道结构通常是由 ReferencePipeline 类实现的,前面讲解 Stream 包结构时,我提到过 ReferencePipeline 包含了 Head、StatelessOp、StatefulOp 三种内部类。
Head 类主要用来定义数据源操作,在我们初次调用 names.stream() 方法时,会初次加载 Head 对象,此时为加载数据源操作;接着加载的是中间操作,分别为无状态中间操作 StatelessOp 对象和有状态操作 StatefulOp 对象,此时的 Stage 并没有执行,而是通过 AbstractPipeline 生成了一个中间操作 Stage 链表;当我们调用终结操作时,会生成一个最终的 Stage,通过这个 Stage 触发之前的中间操作,从最后一个 Stage 开始,递归产生一个 Sink 链。