You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Stream按acct分组求和无需新建Sample对象的优化方案

更优实现方案

你当前写法的核心开销来自merge阶段每合并一个元素就新建一次Sample对象,完全可以通过复用分组对应的汇总实例的方式避免重复创建对象,有两种常用实现,按需选择即可。

方案1:直接修改toMap的merge逻辑(最小改动)

不需要调整整体代码结构,只需要修改merge函数的逻辑,不再新建对象返回,而是把新元素的金额直接累加到Map中已存在的Sample实例上,修改后返回已有实例即可:

Map<String, Sample> map = collectedTxs.stream()
        .collect(Collectors.toMap(
                Sample::getAcct,
                Function.identity(),
                (existSample, newSample) -> {
                    // 直接在已存入Map的实例上累加金额,无新对象创建
                    existSample.setAmt1(safeAdd(existSample.getAmt1(), newSample.getAmt1()));
                    existSample.setAmt2(safeAdd(existSample.getAmt2(), newSample.getAmt2()));
                    return existSample;
                },
                LinkedHashMap::new
        ));

注意事项

  • 要求Sample实体类为amt1、amt2提供setter方法
  • 该方案会修改原始集合中每个acct对应第一条数据的Sample字段值,适合允许修改原始元素的场景
  • 可以抽通用方法做BigDecimal空指针防护:
private static BigDecimal safeAdd(BigDecimal a, BigDecimal b) {
    return (a == null ? BigDecimal.ZERO : a).add(b == null ? BigDecimal.ZERO : b);
}

方案2:自定义collect逻辑(不修改原始元素+最少对象创建)

如果业务不允许修改原始集合中的Sample对象,可以自定义Stream的collect逻辑,每个acct分组仅在首次出现时新建1次汇总用的Sample实例,后续所有同组元素直接在这个汇总实例上累加,不会重复创建对象:

Map<String, Sample> sumMap = collectedTxs.stream()
        .collect(LinkedHashMap::new,
                (resultMap, currentItem) -> {
                    Sample sumInstance = resultMap.get(currentItem.getAcct());
                    if (sumInstance == null) {
                        // 每个分组仅新建1次汇总对象,不引用原始集合元素
                        sumInstance = new Sample(
                                currentItem.getId(),
                                currentItem.getAcct(),
                                currentItem.getAmt1(),
                                currentItem.getAmt2()
                        );
                        resultMap.put(currentItem.getAcct(), sumInstance);
                    } else {
                        // 同组后续元素直接累加,无新对象创建
                        sumInstance.setAmt1(safeAdd(sumInstance.getAmt1(), currentItem.getAmt1()));
                        sumInstance.setAmt2(safeAdd(sumInstance.getAmt2(), currentItem.getAmt2()));
                    }
                },
                LinkedHashMap::putAll
        );

方案优势

  • 每个acct分组最多创建1个Sample对象,相比原实现每合并一个元素就new对象的开销低很多
  • 汇总用的Sample是独立新建的实例,累加操作完全不会修改原始集合中的任何元素,兼容性更好
  • 同样可以复用上面的safeAdd方法做空值防护

内容的提问来源于stack exchange,提问作者Alvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 05:06:48