averagingInt() 返回 Double 而非 int,因平均值可能含小数(如 85 和 86 得 85.5),Java 为保精度直接返回 Double;空集合时返回 NaN,需显式处理;要求方法引用返回基本类型 int,否则可能抛 NullPointerException。

averagingInt() 返回的是 Double,不是 int
很多人以为 averagingInt() 会返回整数平均值,结果发现类型是 Double。这是因为平均值天然可能带小数,哪怕所有成绩都是整数——比如 85 和 86 的平均值是 85.5。Java 设计上直接返回 Double 避免精度丢失或强制截断。
实操建议:
- 声明接收变量时用
Double或double,别写成int avg = list.stream().collect(Collectors.averagingInt(...))(编译失败) - 如果真要取整,得显式调用
Math.round()或intValue(),但要注意:后者直接截断小数,85.9会变成85 - 示例:
Double avg = students.stream().collect(Collectors.averagingInt(Student::getScore));
Student::getScore 必须是非 null 且返回 int
averagingInt() 内部调用的是 ToIntFunction,它要求方法引用或 lambda 必须返回基本类型 int。如果 getScore() 返回的是 Integer(包装类),且存在 null 值,运行时会抛出 NullPointerException。
实操建议:
- 确认
getScore()方法签名是public int getScore(),不是public Integer getScore() - 如果数据源可能含
null成绩,先过滤:.filter(s -> s.getScore() != null)
,或者改用averagingDouble()配合mapToDouble处理空值逻辑 - 避免在 lambda 里做复杂计算,比如
s -> s.getScore() * 1.0会破坏int约束,导致编译错误
空集合时 averagingInt() 返回 NaN,不是 0
当学生列表为空时,averagingInt() 不会抛异常,也不会返回 0,而是返回 Double.NaN。这容易被忽略,后续如果直接做比较(如 avg > 60)或打印,可能引发逻辑错误或显示 “NaN” 字符串。
实操建议:
- 业务上需要默认值时,别依赖 collect 结果本身,而应后置判断:
Double avg = students.stream().collect(Collectors.averagingInt(Student::getScore));<br>if (avg.isNaN()) { avg = 0.0; } - 更稳妥的方式是用
Collectors.collectingAndThen()包装,默认返回 0:Collectors.collectingAndThen(Collectors.averagingInt(Student::getScore), d -> d.isNaN() ? 0.0 : d)
- 注意:不能用
Objects.requireNonNull(avg, "no students"),因为NaN是合法的Double值,不为null
性能和替代方案:大数据量时慎用 averagingInt()
averagingInt() 底层是先求和再除以计数,看似简单,但它要求遍历全程不可中断,且无法并行优化求和与计数的顺序(虽然 Stream 可并行,但 averagingInt 的 collector 不是完全无状态的)。对超大集合,不如手动拆解为 summingInt + counting,再自己算平均值,便于加日志、监控或提前终止。
实操建议:
- 单次统计且数据量 averagingInt() 没问题;超过百万级,考虑:
long sum = students.stream().mapToInt(Student::getScore).sum();<br>long count = students.size(); // 或 .count(),但注意两次遍历开销<br>Double avg = count == 0 ? Double.NaN : (double) sum / count;
- 如果已用并行流,
averagingInt()是线程安全的,但并行未必更快——小集合下线程调度开销可能反超收益
空集合返回 NaN 这点最容易漏测,尤其单元测试只覆盖了有数据的 case。上线后遇到空班、退课潮之类场景,平均分突然变 NaN,前端显示异常,排查起来反而比逻辑错误更费时间。











