summingInt是专用于groupingBy的下游收集器,接收ToIntFunction提取int字段求和;不可单独使用,需嵌套在groupingBy第二参数,如groupingBy(Order::getUserId, summingInt(Order::getAmount))。

用 summingInt 计算分组后某属性的总和,核心是配合 Collectors.groupingBy 使用,它本身不直接分组,而是作为下游收集器(downstream collector)汇总整型字段。
明确 summingInt 的定位
summingInt 是一个「下游收集器」,必须嵌套在 groupingBy 的第二个参数位置,不能单独使用。它接收一个 ToIntFunction,用于从每个元素中提取要累加的 int 值。
- 错误写法:
list.stream().collect(Collectors.summingInt(...))→ 这只能算全部总和,不分组 - 正确结构:
groupingBy(分类键, summingInt(提取字段))
基础用法:按单个字段分组求和
比如统计订单按用户 ID 分组的总金额(假设金额是 int 类型):
Map<Integer, Integer> userTotalAmount = orders.stream()
.collect(Collectors.groupingBy(
Order::getUserId, // 分组键:用户ID
Collectors.summingInt(Order::getAmount) // 每组内对 amount 字段求和
));
结果是 Map<userId, 总金额>,自动处理空组(不会出现 null 值),且线程安全(收集过程无副作用)。
立即学习“Java免费学习笔记(深入)”;
处理非 int 类型或需转换的字段
如果目标字段是 long、double 或包装类(如 Integer),需注意类型匹配:
- 字段是
Long?用summingLong,别强转成 int 否则可能溢出 - 字段是
Integer包装类?summingInt可自动拆箱,但遇到 null 会抛NullPointerException - 需要过滤 null 或做默认值?先用
filter或改用summingInt(x -> x.getAmount() != null ? x.getAmount() : 0)
结合其他收集器做更复杂聚合
summingInt 可与其他下游收集器组合,比如同时求和与计数:
Map<String, Map.Entry<Integer, Long>> result = list.stream()
.collect(Collectors.groupingBy(
Item::getCategory,
Collectors.collectingAndThen(
Collectors.teeing(
Collectors.summingInt(Item::getPrice),
Collectors.counting(),
SimpleEntry::new
),
e -> new AbstractMap.SimpleEntry<>(e.getKey(), e.getValue())
)
));
不过这种写法略重,日常只需总和时,坚持用 summingInt 最简洁直接。


















