Java8 Stream如何按ID和日期分组并合并订单金额?
简化同ID同日期订单金额合并的实现
需求说明
需要将订单列表中相同ID且相同日期的订单金额合并,最终返回合并后的Order列表,而非Map结构。
原实现的问题
原代码通过两次嵌套分组(先按ID分组,再按日期分组),再循环合并结果,步骤繁琐且不够直观。
简化实现方案
可以直接使用复合分组键(将ID和日期组合为唯一键),配合Collectors的分组与合并工具,一步完成分组、合并与结果转换。
方案1:基于自定义Collector的实现
利用AbstractMap.SimpleEntry作为复合分组键,结合自定义Collector合并订单:
import java.util.AbstractMap; import java.util.List; import java.util.stream.Collectors; // 保留原Order类的accept和combine方法 List<Order> mergedOrders = orders.stream() // 按ID+日期的复合键分组 .collect(Collectors.groupingBy( order -> new AbstractMap.SimpleEntry<>(order.getId(), order.getDate()), // 自定义Collector:创建新Order并合并金额 Collector.of( Order::new, Order::accept, Order::combine ) )) // 提取分组后的合并结果,转为List .values() .stream() .collect(Collectors.toList());
方案2:基于reducing的更简洁实现
优化Order类,添加纯函数式的合并方法,配合Collectors.reducing简化代码:
首先修改Order类,添加静态合并方法(避免修改原对象的副作用):
import java.time.LocalDate; public class Order { private Integer id; private LocalDate date; private double amount; // 自行补充构造方法、getter、setter // 纯函数式合并:返回新订单,不修改原对象 public static Order merge(Order order1, Order order2) { Order merged = new Order(); merged.setId(order1.getId()); merged.setDate(order1.getDate()); merged.setAmount(order1.getAmount() + order2.getAmount()); return merged; } }
然后使用reducing完成合并:
List<Order> mergedOrders = orders.stream() .collect(Collectors.groupingBy( order -> new AbstractMap.SimpleEntry<>(order.getId(), order.getDate()), // 使用reducing合并同组订单 Collectors.reducing(new Order(), Order::merge) )) .values() .stream() .collect(Collectors.toList());
方案优势
- 一步完成分组与合并,代码简洁直观
- 避免嵌套循环与中间Map的繁琐处理
- 纯函数式的合并方法(方案2)无副作用,更安全可靠
内容的提问来源于stack exchange,提问作者Knowhen
相关产品推荐
相关产品推荐

