1. 概述

Java 的 Stream API 是我们处理数据集合时的常用利器。

它内置了对数值流的支持,比如可以直接调用 sum() 方法进行求和。✅
但⚠️需要注意的是:这种原生的 sum() 支持仅限于部分基本数值类型,像 BigDecimal 这种高精度类型并不在其中。

本文将带你解决这个问题:如何对 BigDecimal 类型的流进行求和操作。

2. 常见的数值流求和方式

Stream API 提供了专门的数值流类型,如 IntStreamDoubleStreamLongStream,它们都自带 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() 方法仅支持 intlongdouble 及其对应的流类型。
  • BigDecimal 没有对应的 BigDecimalStream,无法直接调用 sum()
  • ✅ 使用 reduce(identity, BigDecimal::add) 是最直接可靠的替代方案。
  • reduce 更通用,适合自定义聚合逻辑,是处理非基本类型数值求和的标配解法。

所有示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-streams-3


原始标题:Add BigDecimals using the Stream API