Stream流的介绍
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
- Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
- 和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
ps:介绍内容来自菜鸟教程
Stream流的创建
- 常用的集中创建方式
- 使用集合创建
Collection接口中的stream()方法和parallelStream()方法,
stream()是顺序流,parallelStream()并行流 - 使用数组创建
Arrays类中的stream()方法 - 使用对象创建
Stream类中的of()方法 - 创建无限流
Stream类中的iterate()方法和generate()方法
- 使用集合创建
//创建两个对象
UserIdNameVO user1 = new UserIdNameVO();
user1.setUSER_ID("1");
user1.setNAME("张三");
UserIdNameVO user2 = new UserIdNameVO();
user2.setUSER_ID("2");
user2.setNAME("李四");
//使用数组创建流
UserIdNameVO[] userArr = {user1,user2,user3};
Stream<UserIdNameVO> stream1 = Arrays.stream(userArr);
//使用集合创建流
Stream<UserIdNameVO> stream2 = userList.stream();
//使用对象创建流
Stream<UserIdNameVO> stream3 = Stream.of(user1,user2,user2,user2,user2);
//创建无限流
Stream<Integer> stream4 = Stream.iterate(1, x -> x + 3);
stream4.limit(100).forEach(x -> System.out.println(x));
Supplier<UUID> randomUUIDSupplier = UUID::randomUUID;
Stream<UUID> infiniteStreamOfRandomUUID = Stream.generate(randomUUIDSupplier);
infiniteStreamOfRandomUUID.limit(3).forEach(System.out::println);
注意:无限流不设置长度会一直执行下去,此处使用limit方法设置长度
流的中间操作和终止操作
所有流操作分为中间操作与终止操作两类,并被组合为管道流形式。
管道流由源(比如集合、数组,生成器函数,i/o channel,无限序列生成器),接着是零个或多个中间操作和一个终止操作。
中间操作只有终止操作执行时才执行。它们以管道流形式直播执行,可以通过下列方法加入管道流:
终止操作可以遍历流生成结果或直接消费。终止操作执行后,可以认为管道流被消费了并不能再被使用。几乎在所有情况下,终端操作都是立即执行的,在返回之前完成对数据源的遍历和对管道的处理。
中间操作方法
filter() 用于通过设置的条件过滤出元素
map() 用于映射每个元素到对应的结果
flatMap() 把Stream中的层级结构扁平化,就是将最底层元素抽出来放到一起(可将每个元素的流分割成更细的流然后返回一个新流)
distinct() 结果去重
sorted() 对流进行排序
peek() 和Map差不多,map可以改变返回值类型,而peek无法改变返回值类型
limit() 用于获取指定数量的流
skip() 跳过stream中的前n个元素在执行
所有中间操作是懒执行,即直到实际需要处理结果时才会执行。执行中间操作实际上并不执行任何操
作,而是创建一个新的流,当遍历该流时,它包含与给定谓词匹配的原始流的元素。因此在执行管道
的终止操作之前,流的遍历不会开始。
终止操作方法
forEach() 循环
forEachOrdered() 主要区别在并行处理上,forEach是并行处理的,forEachOrder是按顺序处理的
toArray() 流转数组
reduce()
collect() 将原来的Stream映射为一个单元素流,然后收集,Collectors.toList(),Collectors.toMap()等
min()
max()
count() 返回元素数量
anyMatch() anyMatch表示,判断的条件里,任意一个元素成功,返回true
allMatch() allMatch表示,判断条件里的元素,所有的都是,返回true
noneMatch() oneMatch跟allMatch相反,判断条件里的元素,所有的都不是,返回true
findFirst() 返回第一个元素
findAny() 并行情况下随机返回一个元素
一些基本使用方法(筛选、转换对象、转Map、查询最大)
//过滤筛选出叫王五的信息
List<UserIdNameVO> userIdNameVOS = stream1.filter(user -> user.getNAME().equals("王五")).collect(Collectors.toList());
//把所有用户名拿出来
List<String> userIdNameVOS = stream1.map(UserIdNameVO::getNAME).collect(Collectors.toList());
//把用户的ID变成Map的key,name变成Map的value
Map<String, String> userMap = stream1.collect(Collectors.toMap(UserIdNameVO::getUSER_ID, UserIdNameVO::getNAME));
//找出ID最大的那个用户返回
UserIdNameVO userIdNameVO = stream1.max((a, b) -> {
if (Integer.valueOf(a.getUSER_ID()) > Integer.valueOf(b.getUSER_ID())) {
return 1;
} else {
return -1;
}
}).get();