Java Stream - tenji/ks GitHub Wiki
Stream 作为 Java8 的新特性,基于 lambda 表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。
将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
- 中间操作
map (mapToInt, flatMap 等), filter, distinct, sorted, peek, limit, skip, parallel, sequential, unordered
- 终止操作
forEach, forEachOrdered, toArray, reduce, collect, min, max, count, anyMatch, allMatch, noneMatch, findFirst, findAny, iterator
- stream():为集合创建串行流
- parallelStream():为集合创建并行流
使用用例涉及的类定义:(集合对象为订单对象,主键、订单号、订单类型、总金额)
class OrderInfo {
private Integer id;
private String orderNo;
private Integer type;
private Double total;
public OrderInfo(Integer id, String orderNo, Integer type, Double total) {
this.id = id;
this.orderNo = orderNo;
this.type = type;
this.total = total;
}
}
方法定义:
Stream<T> filter(Predicate<? super T> predicate);
使用样例:
# 过滤掉总金额小于一百万的订单
List<OrderInfo> orderList = list.stream()
.filter(orderInfo -> orderInfo.getTotal() >= 1000 * 1000)
.collect(Collectors.toList());
Stream 的 Map-Reduce 操作是 Java 函数式编程的精华所在,同时也是最为复杂的部分。但一旦你啃下了这块硬骨头,那你就真正熟悉 Java 的函数式编程了。
map 操作又称为映射操作,是处理 Stream 的重要操作。它的作用是将当前 Stream 中的每个元素都映射转换为另一个元素,从而得到一个新的 Stream。转换前后的元素类型也可以不同。
方法定义:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
使用样例:
# 以数组的形式输出订单金额前十的订单
double[] orderArray = list.stream()
.sorted(Comparator.comparing(OrderInfo::getTotal).reversed())
.limit(10)
.mapToDouble(OrderInfo::getTotal)
.toArray();
map 方法是一个中间操作,作用是将当前 Stream 中的每个元素通过参数 mapper 转换为另一个元素,转换前的元素类型为 T,转换后的元素类型为 R。
方法定义:
Stream<T> distinct();
方法定义:
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
使用样例:
# 按照 ID 进行排序
List<OrderInfo> orderList = list.stream()
.sorted(Comparator.comparing(OrderInfo::getId))
.collect(Collectors.toList());
# 按照 ID 进行倒序
List<OrderInfo> orderList = list.stream()
.sorted(Comparator.comparing(OrderInfo::getId).reversed())
.collect(Collectors.toList());
# 先按照订单类型排序,再按照订单总金额排序
List<OrderInfo> orderList = list.stream()
.sorted(Comparator.comparing(OrderInfo::getId).thenComparing(OrderInfo::getTotal))
.collect(Collectors.toList());
通过 Comparator.thenComparing(Comparator<? super T> other)
实现,可参考以上第三个样例。
Stream 的 limit 方法返回一个新的流,该流的元素被截断为给定的最大长度。limit 方法包含前 n 个元素,其中 n 小于或等于给定的最大大小。
方法定义:
Stream<T> limit(long maxSize);
使用样例:
# 按照订单总金额排序,且只返回前三条数据
List<OrderInfo> orderList = list.stream()
.sorted(Comparator.comparing(OrderInfo::getTotal)).limit(3)
.collect(Collectors.toList());
reduce 操作(reduction operation),翻译为规约操作,是 Stream 中最复杂的操作。
规约操作,是通过重复执行指定的合并操作(combining operation),将 Stream 中的所有元素合并得到一个汇总结果的过程。例如,求和(sum)、求最大或最小值(max / min)、求平均数(average)、求元素总个数(count)、将所有元素汇总到一个列表(collect),这些都属于规约操作。
规约操作都属于终止操作(terminal operations)。
Stream 类库有两个通用的规约操作 reduce()
和 collect()
。
Stream.max() 根据提供的 Comparator 返回流的最大元素。比较器是一种比较函数,它对某些对象集合施加总排序。 max() 是一种终端操作,它组合流元素并返回摘要结果。因此,max() 是归约(reduce)的一种特殊情况。该方法返回 Optional 实例。
方法定义:
Optional<T> max(Comparator<? super T> comparator);
使用样例:
# 获取金额最大的订单
OrderInfo orderInfo = list.stream()
.max(Comparator.comparing(OrderInfo::getTotal)).get();
不执行终止操作,是否可以获取集合的大小?
不可以。因为 streams 可以是无限的或按需生成输出。