使用Collectors.groupingBy按业务维度分组并汇总成本支出,需配合下游收集器如summingDouble求和;支持单维度、多维度分组及保留明细列表,注意处理null值和浮点精度问题。

用 Collectors.groupingBy 按业务维度(比如部门、项目、成本类型)汇总成本支出,核心是把成本对象按某个属性分组,再对每组做聚合(如求和)。关键不在分组本身,而在“汇总”——需配合下游收集器(如 Collectors.summingDouble)一起使用。
明确成本对象结构和分组字段
假设你有如下成本实体类:
public class CostItem {
private String department; // 业务维度:部门
private String project; // 业务维度:项目
private String costType; // 业务维度:成本类型(差旅/办公/人力等)
private double amount; // 支出金额
// 构造、getter 省略
}
你要按哪个维度汇总,就用哪个字段做分组键。例如按部门汇总总支出,就用 CostItem::getDepartment;按“部门+项目”组合汇总,就用自定义键(如 Map.entry(dept, proj) 或封装对象)。
单维度分组求和(最常用)
直接按一个字段分组,并对金额求和:
List<CostItem> costs = ...;
Map<String, Double> deptTotal = costs.stream()
.collect(Collectors.groupingBy(
CostItem::getDepartment,
Collectors.summingDouble(CostItem::getAmount)
));
结果形如:{"研发部"=12500.0, "市场部"=8760.0, "行政部"=3200.0}。这是最简洁高效的写法。
多维度分组或带明细的汇总
如果需要同时按多个字段分组,或保留每组的原始明细列表,可这样处理:
- 按部门+成本类型二维分组求和:
Map<Map.Entry<String,String>, Double> result = costs.stream()<br> .collect(Collectors.groupingBy(<br> cost -> Map.entry(cost.getDepartment(), cost.getCostType()),<br> Collectors.summingDouble(CostItem::getAmount)<br> )); - 按部门分组并保留明细列表(便于后续计算均值、最大值等):
Map<String, List<CostItem>> deptItems = costs.stream()<br> .collect(Collectors.groupingBy(CostItem::getDepartment));
后续可遍历每个List<CostItem>手动计算,或链式调用:.collect(Collectors.groupingBy(CostItem::getDepartment,<br> Collectors.collectingAndThen(Collectors.toList(), list -> ...)));
注意空值与精度问题
成本金额建议用 BigDecimal 存储,避免浮点误差。若必须用 double,分组前先过滤掉 null 金额项:
.filter(cost -> cost.getAmount() > 0)
若分组键可能为 null(如未填部门),默认会归入 null 键,可提前映射为占位符:
cost -> Optional.ofNullable(cost.getDepartment()).orElse("未分配")

















