Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构, 讲的是数据,而 Stream 是有关计算的,讲的是计算。前者是主要面向内存, 存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新 Stream。
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果。
- Stream 一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。
Stream 的操作三个步骤
1- 创建 Stream:一个数据源(如:集合、数组),获取一个流
Integer[] nums = {11, 2, 4, 7, 0, 1, 1, 7};
// 方式一:通过集合
List<Integer> list = Arrays.asList(nums);
// 顺序流
Stream<Integer> stream = list.stream();
// 并行流
Stream<Integer> stream1 = list.parallelStream();
// 方式二:通过数组
Stream<Integer> stream2 = Arrays.stream(nums);
// 方式三:通过Stream的of()
Stream<String> stream3 = Stream.of("A", "B", "D", "C");
2- 中间操作:每次处理都会返回一个持有结果的新 Stream,即中间操作的方法 返回值仍然是 Stream 类型的对象。因此中间操作可以是个操作链,可对数据源的数据进行 n 次处理,但是在终结操作前,并不会真正执行。
// 筛选与切片
// filter() 过滤
stream.filter(num -> num > 3).forEach(System.out :: println); // 11, 4, 7, 7
System.out.println();
// limit() 截断,使元素不超过给定数量
// stream.limit(2).forEach(System.out :: println); // 错误,上一行forEach已将stream终止
list.stream().filter(num -> num > 3).limit(2).forEach(System.out :: println); // 11, 4
System.out.println();
// skip() 跳过前n个元素,若流中元素不足n,返回一个空流
list.stream().skip(2).forEach(System.out :: println); // 4, 7, 0, 1, 1, 7
System.out.println();
// distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
list.stream().distinct().forEach(System.out :: println); // 11, 2, 4, 7, 0, 1
System.out.println();
// 映射
// map(Function f) 接收一个函数作为参数,将元素转换成其他形式或提取信息,
// 该函数会被应用到每个元素上,并将其映射成一个新的元素
stream3.map(String :: toLowerCase).forEach(System.out :: println); // a, b, d, c
System.out.println();
// 排序
// 自然排序
list.stream().sorted().forEach(System.out :: println); // 0, 1, 1, 2, 4, 7, 7, 11
System.out.println();
// 定制排序
list.stream().sorted((o1, o2) -> o2 - o1).forEach(System.out :: println); // 11, 7, 7, 4, 2, 1, 1, 0
3- 终止操作(终端操作):终止操作的方法返回值类型就不再是 Stream 了,因此 一旦执行终止操作,就结束整个 Stream 操作了。一旦执行终止操作,就执行中间操作链,最终产生结果并结束 Stream。
// 匹配与查找
// allMatch(Predicate p) 检查是否匹配所有元素
boolean a1 = list.stream().allMatch(num -> num > 0);
System.out.println(a1); // false
// anyMatch(Predicate p) 检查是否匹配至少一个元素
a1 = list.stream().anyMatch(num -> num > 0);
System.out.println(a1); // true
// findFirst() 返回第一个元素
System.out.println(list.stream().findFirst()); // Optional[11]
System.out.println(list.stream().findFirst().get()); // 11
// count 返回流中的总个数
System.out.println(list.stream().count()); // 8
// max(Comparator c) 返回流中最大值(排序完最右边的值)
System.out.println(list.stream().max((o1, o2) -> o1 - o2)); // Optional[11]
System.out.println(list.stream().max((o1, o2) -> o2 - o1)); // Optional[0]
// min(Comparator c) 返回流中最小值
System.out.println(list.stream().min((o1, o2) -> o1 - o2)); // Optional[0]
System.out.println(list.stream().min((o1, o2) -> o2 - o1)); // Optional[11]
// forEach(Consumer c) 内部迭代
list.stream().forEach(System.out :: println); // 11, 2, 4, 7, 0, 1, 1, 7
// 归约
// reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
System.out.println(list.stream().reduce(0, (o1, o2) -> o1 + o2)); // list中数的和,identity为初始值 33
// 收集
// collect(Collector c) 将流转换为其他形式。接收一个 Collector 接口的实现,用于给 Stream 中元素做汇总的方法
List<Integer> list2 = list.stream().collect(Collectors.toList());
System.out.println(list2); // [11, 2, 4, 7, 0, 1, 1, 7]
Set<Integer> set = list.stream().collect(Collectors.toSet());
System.out.println(set); // [0, 1, 2, 4, 7, 11]
// toCollection Collector<T, ?, C> 把流中元素收集到创建的集合
Collection<Integer> co = list.stream().collect(Collectors.toCollection(ArrayList::new));
System.out.println(co); // [11, 2, 4, 7, 0, 1, 1, 7]
// counting Collector<T, ?, Long> 计算流中元素的个数
System.out.println(list.stream().collect(Collectors.counting())); // 8
// summingInt Collector<T, ?, Integer> 对流中元素的整数属性求和
// averagingInt Collector<T, ?, Double> 计算流中元素 Integer 属性的平均值
// summarizingInt Collector<T, ?, IntSummaryStatistics> 收集流中 Integer 属性的统计值。如:平均值
// joining Collector<CharSequence, ?, String> 连接流中每个字符串
// maxBy Collector<T, ?, Optional> 根据比较器选择最大值
// minBy Collector<T, ?, Optional> 根据比较器选择最小值
// reducing Collector<T, ?, Optional> 从一个作为累加器的初始值开始,利用BinaryOperator 与流中元素逐个结合,从而归约成单个值
// collectingAndThen Collector<T,A,RR> 包裹另一个收集器,对其结果转换函数
// groupingBy Collector<T, ?, Map<K, List>> 根据某属性值对流分组,属性为K,结果为 V
// partitioningBy Collector<T, ?, Map<Boolean, List>> 根据 true 或 false 进行分区