
本文介绍如何用 Java Stream 的 Collectors.groupingBy 与 Collectors.reducing 组合,仅遍历一次列表即可完成多种类型条件的金额汇总,避免重复流操作带来的性能损耗。
本文介绍如何用 java stream 的 `collectors.groupingby` 与 `collectors.reducing` 组合,仅遍历一次列表即可完成多种类型条件的金额汇总,避免重复流操作带来的性能损耗。
在实际业务开发中,我们常需根据对象属性(如 type)对集合进行多维度分类求和。原始代码中,针对每类条件(如 "A"、"B"、未知类型等)分别调用 .stream().filter().map().reduce(),导致列表被遍历 6 次以上,时间复杂度为 O(6n),不仅低效,还难以维护。
更优解是:单次遍历 + 分组聚合。Java 8+ 的 Collectors.groupingBy 支持嵌套下游收集器,配合 Collectors.reducing 可直接实现按 type 分组并累加 amount,生成 Map
Map<string bigdecimal> typeToSum = list.stream()
.collect(Collectors.groupingBy(
x -> Optional.ofNullable(x.getType()).orElse(""),
Collectors.mapping(
Account::getAmount,
Collectors.reducing(
BigDecimal.ZERO,
BigDecimal::add
)
)
));</string>
✅ 关键优化点:
- Optional.ofNullable(x.getType()).orElse("") 统一处理 null 和空字符串为 "",确保归入同一组;
- Collectors.mapping(..., reducing(...)) 在分组过程中直接完成 amount 累加,无需额外 map/reduce;
- 整个过程仅遍历列表 1 次,时间复杂度降至 O(n)。
随后,可基于该 Map 安全提取各分类值,并映射到 Account 对象:
BigDecimal aSum = typeToSum.getOrDefault("A", BigDecimal.ZERO)
.add(typeToSum.getOrDefault("H", BigDecimal.ZERO));
BigDecimal bSum = typeToSum.getOrDefault("B", BigDecimal.ZERO);
BigDecimal cSum = typeToSum.getOrDefault("C", BigDecimal.ZERO);
BigDecimal fSum = typeToSum.getOrDefault("F", BigDecimal.ZERO);
BigDecimal unknownSum = typeToSum.getOrDefault("", BigDecimal.ZERO);
BigDecimal othSum = Stream.of("A", "B", "C", "F", "H")
.map(typeToSum::getOrDefault)
.reduce(BigDecimal.ZERO, BigDecimal::add)
.negate() // 注意:此处需先求已知总和,再用 total - 已知 得 others
.add(typeToSum.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
// 更推荐显式计算 others:totalAll - (aSum + bSum + cSum + fSum + unknownSum + hSum)
BigDecimal totalAll = typeToSum.values().stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal othSum = totalAll.subtract(aSum)
.subtract(bSum)
.subtract(cSum)
.subtract(fSum)
.subtract(unknownSum);
⚠️ 注意事项:
- 原始代码中 othSum 的逻辑存在重叠(如 "H" 同时计入 aSum 和 othSum),需明确定义业务规则;
- 若需严格区分 "A"/"H" 与 "others",建议先明确分类枚举或白名单,再用 Set.of("A","H","B","C","F").contains(type) 判断;
- 对于高频调用场景,可进一步封装为通用方法,接收 Function
分组键与 Function 映射值。
总结:用 groupingBy + reducing 替代多次 filter-map-reduce,是 Stream API 中提升聚合效率的经典实践——既精简代码、增强可读性,又显著降低时间开销,尤其适用于大数据量或高并发服务场景。










