1. 概述
Java 的 Stream API 是我们处理数据集合时的常用利器。
它内置了对数值流的支持,比如可以直接调用 sum()
方法进行求和。✅
但⚠️需要注意的是:这种原生的 sum()
支持仅限于部分基本数值类型,像 BigDecimal
这种高精度类型并不在其中。
本文将带你解决这个问题:如何对 BigDecimal
类型的流进行求和操作。
2. 常见的数值流求和方式
Stream API 提供了专门的数值流类型,如 IntStream
、DoubleStream
和 LongStream
,它们都自带 sum()
方法。
来看几个典型用法:
IntStream intNumbers = IntStream.range(0, 3);
assertEquals(3, intNumbers.sum());
对于包装类型的集合(如 List<Double>
),可以通过 mapToDouble
转成数值流后再求和:
List<Double> doubleNumbers = Arrays.asList(23.48, 52.26, 13.5);
double result = doubleNumbers.stream()
.mapToDouble(Double::doubleValue)
.sum();
assertEquals(89.24, result, .1);
看起来很丝滑对吧?但如果你试图对 List<BigDecimal>
做类似操作,会发现 ❌ 根本没有 BigDecimalStream
这个东西。
所以这条路走不通,得换思路。
3. 使用 reduce 实现 BigDecimal 求和
既然没有原生 sum()
,我们可以退一步,使用更通用的 Stream.reduce
方法。✅
reduce
是一个聚合操作,适用于任何可“合并”的类型,不只是数字。
先看一个整数的例子热热身:
Stream<Integer> intNumbers = Stream.of(5, 1, 100);
int result = intNumbers.reduce(0, Integer::sum);
assertEquals(106, result);
现在换成 BigDecimal
,套路完全一样:
Stream<BigDecimal> bigDecimalNumber =
Stream.of(BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN);
BigDecimal result = bigDecimalNumber.reduce(BigDecimal.ZERO, BigDecimal::add);
assertEquals(11, result);
reduce 方法的两个关键参数:
- Identity(恒等值):相当于加法中的 0,是累加的起点。对于加法,通常用
BigDecimal.ZERO
。 - Accumulator Function(累加器函数):接收两个参数 —— 当前累计值和下一个元素,返回新的累计值。这里我们用
BigDecimal::add
。
⚠️ 踩坑提醒:
别用 new BigDecimal("0")
作为 identity,直接用 BigDecimal.ZERO
更高效且不易出错。
这个方案简单粗暴,而且✅ 适用于任何支持“合并”语义的类型,不局限于数字。
4. 总结
- 原生
sum()
方法仅支持int
、long
、double
及其对应的流类型。 - ❌
BigDecimal
没有对应的BigDecimalStream
,无法直接调用sum()
。 - ✅ 使用
reduce(identity, BigDecimal::add)
是最直接可靠的替代方案。 reduce
更通用,适合自定义聚合逻辑,是处理非基本类型数值求和的标配解法。
所有示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-streams-3