You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java中使用Stream对Integer集合求和避免溢出的方法

这个问题我之前也碰到过!当你用mapToInt求和时,哪怕单个元素都远小于Integer.MAX_VALUE,只要元素数量足够多,总和很容易就超出int的范围,触发静默溢出,结果完全不对。下面给你两种靠谱的解决方案:

解决方案一:转成long类型求和

这是最常用的方案,因为long的取值范围(-9223372036854775808 到 9223372036854775807)比int大得多,绝大多数业务场景下都能避免溢出。只需要把mapToInt换成mapToLong就行:

Set<Integer> numbers = new HashSet<>();
// 填充集合的代码
long sum = numbers.stream().mapToLong(Integer::longValue).sum();

这里Integer::longValue会把每个Integer对象转成long基本类型,最后sum()返回的是long类型,完美避开int的溢出问题。

解决方案二:用BigInteger实现无溢出求和

如果你的元素数量多到连long都兜不住(比如几十亿个接近Integer.MAX_VALUE的元素),那就要用BigInteger来求和,它支持任意大小的整数运算,完全不会溢出。代码如下:

Set<Integer> numbers = new HashSet<>();
// 填充集合的代码
BigInteger total = numbers.stream()
    .map(BigInteger::valueOf)
    .reduce(BigInteger.ZERO, BigInteger::add);

简单解释下逻辑:

  • map(BigInteger::valueOf)把每个Integer转成BigInteger对象
  • reduce方法以BigInteger.ZERO为初始值,通过BigInteger::add把所有元素累加起来

这种方式绝对安全,但因为是对象操作,性能会比基本类型的流稍差一点,不过在需要绝对避免溢出的场景下,这点性能损耗完全值得。

补充:为什么原来的代码会溢出?

Java的整数溢出是静默的——当总和超过Integer.MAX_VALUE时,不会抛出异常,而是直接按照二进制补码规则循环计算,结果会变成一个错误的负数或者小正数,很难排查。比如把多个Integer.MAX_VALUE相加,得到的结果会完全不符合预期。

你可以根据自己的业务场景选择对应的方案哦!

内容的提问来源于stack exchange,提问作者bisarch

火山引擎 最新活动