Collectors.summarizingInt()可一次性获取计数、总和、均值、最小值、最大值,无需多次遍历或手动封装;它接收对象流及ToIntFunction提取int字段,要求方法返回int或可拆箱Integer,空值未处理会抛NPE,结果通过getter获取,getSum()返回long防溢出,空集合时getMin()/getMax()返回哨兵值,getAverage()返回0.0而非NaN。

Collectors.summarizingInt() 是 Java 8 Stream API 中最被低估的聚合工具之一——它真能一次性拿到计数、总和、均值、最小值、最大值,且不遍历多次、不手动封装对象。
用法很简单:传入一个 ToIntFunction 提取整型字段
它不是直接接收 int 流,而是接收任意对象流,并靠你提供的函数“抠出”一个 int 值来统计。比如对 List 按年龄汇总:
IntSummaryStatistics stats = people.stream()
.collect(Collectors.summarizingInt(Person::getAge));
注意:Person::getAge 必须返回 int(或自动拆箱的 Integer),不能是 long 或 double,否则编译报错 no suitable method found for summarizingInt(...)。
- 支持的方法引用、Lambda、匿名内部类,只要类型匹配
ToIntFunction - 如果字段可能为
null(如Integer age),而你又没做空值处理,运行时会抛NullPointerException - 均值(
getAverage())返回double,但它是精确计算结果(非截断),小数位数取决于原始数据精度
拿到结果后怎么取值?别调 toString() 就完事
IntSummaryStatistics 是个不可变容器,提供明确的 getter 方法,不是靠解析字符串:
System.out.println(stats.getCount()); // long,不是 int System.out.println(stats.getSum()); // long,防溢出设计 System.out.println(stats.getAverage()); // double,空集合时返回 0.0 System.out.println(stats.getMin()); // int,空集合时返回 Integer.MAX_VALUE System.out.println(stats.getMax()); // int,空集合时返回 Integer.MIN_VALUE
关键点:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
-
getSum()返回long——这是为了在累加过程中避免int溢出,但你传入的每个值仍是int范围内 - 空集合时,
getMin()/getMax()的返回值是哨兵值,不是Optional,需自行判断getCount() == 0再决定是否使用极值 -
getAverage()对空集合返回0.0,不是NaN,这点和直觉相反,容易埋坑
替代方案对比:为什么不用 summarizingLong() 或手动 reduce?
如果你的数据本质是 long(比如毫秒时间戳、ID),硬套 summarizingInt() 会丢失精度或抛异常;这时该用 Collectors.summarizingLong() ——接口完全一致,只是泛型参数和返回类型不同。
手动 reduce() 实现同样功能?可以,但代价高:
- 要自己定义五元组类或用
AbstractMap.SimpleImmutableEntry拼凑 - 合并逻辑复杂(尤其均值和极值的并发安全合并),
IntSummaryStatistics内部已优化为无锁、可并行的累积器 - Stream 并行时,
summarizingInt()自动适配ForkJoinPool分段统计再合并,手动写极易出错
真正容易被忽略的是:它只做「单字段」统计。想同时按城市分组再对每个城市的销售额做汇总?得嵌套用——先 groupingBy(city, summarizingInt(sale::getAmount)),而不是幻想一个 collector 能跨维度聚合。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










