stream().mapToInt().sum() 是对 List<Integer> 或 List<Long> 求和最简单、高效且不易出错的方式,避免装箱开销,但需注意空值、溢出及精度问题。

用 stream().mapToInt().sum() 最简单直接
对 List<Integer> 或 List<Long> 求和,mapToInt().sum() 是最常用、最不易出错的方式。它自动处理空值安全(前提是列表本身不为 null),且底层用的是原始 int 运算,没装箱开销。
常见错误现象:stream().reduce(0, Integer::sum) 看似等价,但实际会触发大量 Integer 装箱 —— 每次加法都新建对象,大数据量时 GC 压力明显。
- 如果元素是
Integer,用list.stream().mapToInt(Integer::intValue).sum() - 如果元素是
Long,改用mapToLong(Long::longValue).sum(),别硬转int防溢出 - 若列表可能为
null,先判空:Optional.ofNullable(list).orElse(Collections.emptyList()).stream()...
reduce 适合带初始值或自定义逻辑的场景
reduce 不是求和专用,它的价值在于可控性:能设初始值、能写任意二元操作、能处理并行流的组合逻辑。但普通求和没必要绕这么远。
使用场景举例:累加时跳过负数、按条件乘系数、或初始值不是 0(比如统计“默认已含 1 个”的总数)。
立即学习“Java免费学习笔记(深入)”;
- 正确写法:
list.stream().reduce(0, (a, b) -> a + b, Integer::sum)—— 第三个参数是并行流合并用的,不能省略或传null - 错误写法:
list.stream().reduce(Integer::sum)返回Optional<Integer>,空列表会抛NoSuchElementException - 如果元素可能为
null,mapToInt会 NPE;此时得先filter(Objects::nonNull)
小心 int 溢出和 Double 精度问题
Java 的 sum() 方法不做溢出检查 —— Integer.MAX_VALUE + 1 直接变负数,静默出错。浮点数用 mapToDouble().sum() 同样有精度丢失风险。
性能影响不大,但业务语义可能崩坏。比如订单金额累加、科学计算、大数统计。
- 需要防溢出:改用
mapToLong()或mapToBigInteger()(需手动reduce) - 需要高精度:用
BigDecimal,但别用double构造器(如new BigDecimal(0.1)),改用字符串构造 -
Collectors.summingInt()和mapToInt().sum()行为一致,只是写法不同,性能无差别
别在循环里反复调用 stream()
有人把求和封装成工具方法,却在 for 循环里对同一个列表反复 stream().mapToInt().sum() —— 每次都新建 Stream 对象、遍历迭代器、触发函数式链路。实测比传统 for 循环慢 3–5 倍。
这不是 Stream 的问题,是误用。Stream 适合「一次声明、一次执行」的数据转换场景。
- 高频调用求和?直接用传统 for:
int sum = 0; for (int v : list) sum += v; - 如果还要过滤/映射再求和,那 Stream 才真正发挥价值
- 注意
ArrayList和LinkedList的stream()性能差异不大,但forEach遍历LinkedList更慢
归约操作容易让人盯着函数式语法看,反而忽略数据源是否可空、类型是否匹配、数值范围是否安全。这些地方一漏,线上就容易出现偶发求和错误,还不好复现。










