Java 8 Stream API单流实现多字段averagingDouble分组统计方法
首先,你可以通过创建一个用于存储分组后平均值的实体类,结合Collectors.groupingBy和Collectors.collectingAndThen、Collectors.reducing,在单个Stream调用中完成分组和多字段平均值统计,无需先分组再遍历计算。
步骤1:创建存储平均值的实体类
先定义一个类来封装每组的两个平均值结果:
class ProductAverage { private final double averageUnits; private final double averageMktVal; public ProductAverage(double averageUnits, double averageMktVal) { this.averageUnits = averageUnits; this.averageMktVal = averageMktVal; } public double getAverageUnits() { return averageUnits; } public double getAverageMktVal() { return averageMktVal; } }
步骤2:单个Stream调用完成分组与统计
在main方法中,替换原来的分组逻辑为以下代码:
Map<String, ProductAverage> result = list1.stream() .collect(Collectors.groupingBy( // 分组键:astcls字段 Product::getAstcls, // 下游收集器:先汇总每组的总和与数量,再计算平均值 Collectors.collectingAndThen( Collectors.reducing( // 初始值:数组索引0=units总和,1=mktVal总和,2=元素数量 new double[3], // 转换每个Product为总和+数量的数组 product -> new double[]{product.getUnits(), product.getMktVal(), 1}, // 合并两组的数组值 (a, b) -> new double[]{a[0] + b[0], a[1] + b[1], a[2] + b[2]} ), // 将汇总的总和与数量转换为平均值对象 totals -> new ProductAverage( totals[0] / totals[2], totals[1] / totals[2] ) ) ));
步骤3:遍历输出结果
最后遍历结果Map即可得到每组的平均值:
result.forEach((astcls, avg) -> { System.out.println("astcls: " + astcls); System.out.println("Average Units: " + avg.getAverageUnits()); System.out.println("Average MktVal: " + avg.getAverageMktVal()); System.out.println("-----"); });
原理说明
Collectors.reducing负责在每组内累加units总和、mktVal总和以及元素数量,用一个数组暂存这三个值。Collectors.collectingAndThen将reducing的结果(汇总数组)转换成ProductAverage对象,通过总和除以数量得到平均值。- 整个逻辑在一次Stream遍历中完成,避免了先分组再二次遍历集合的额外开销。
内容的提问来源于stack exchange,提问作者Jaydeep Chauhan
相关产品推荐
相关产品推荐

