Stream api reduce方法在尝试对大数求和时返回负值[重复]
Posted
技术标签:
【中文标题】Stream api reduce方法在尝试对大数求和时返回负值[重复]【英文标题】:Stream api reduce method returns negative value when trying to sum up large numbers [duplicate] 【发布时间】:2021-08-17 15:19:57 【问题描述】:我正在尝试使用流 api reduce 方法对列表中的数字求和。它为较小的数字提供正确的结果。但是当我给出更大的数字时,它会返回一个不正确的负数。
这是我的代码
public void sumOfNum(List<Integer> numbers)
long result = numbers.stream().reduce(0, (a, b) -> a + b);
System.out.print(result);
测试用例 1(通过)
输入
12345、2343、4324、2323、24234
输出
45569
测试用例 2(失败)
输入
256741038, 623958417,623958417,714532089, 714532089
输出
-1361245246
【问题讨论】:
【参考方案1】:您将它们添加为整数,Java 对整数值 2147483647
有限制。
如果您通过此最大值,您将从最小值开始计数
Integer.MAX_VALUE + 1 = -2147483648
.
【讨论】:
【参考方案2】:您正在使用当前代码执行Integer
添加。我的假设是您知道可能发生的数字溢出,这就是long
类型为result
的原因。一旦您将流的值map
传递到Long
,然后再对它们求和,事情就会到位。
long result = numbers.stream()
.map(Long::valueOf)
.reduce(0L, Long::sum);
或者简单地说:
long result = numbers.stream()
.mapToLong(val -> val)
.sum();
【讨论】:
哪个更好?mapToLong(val -> val)
或 mapToLong(Integer::longValue)
。我假设val -> val
涉及Integer -> int -> long
而第二个只是int -> long
?
@Naman 是的,我知道整数溢出,但我是这个流 API 的新手,我完全忘记了我必须在 sum 之前将 Integer 转换为 long。现在它在将 Integer 转换为 long 后工作正常。谢谢。
@GauthamM 是的,尽管我的怀疑并不完全是你所说的。我怀疑4: i2l
的步骤,即 int 到 long 的转换也是 Integer.longValue
的一部分。没有足够的时间,但我肯定会尽快深入研究。 (在问题中将 Stream 分开,在我看来,这将超出基础知识)
@GauthamM 没有区别,因为不可能有区别。源是Integer
对象,结果是long
。唯一的区别是它发生在哪里。当您使用mapToLong(Integer::longValue)
或mapToLong(i -> i.longValue())
时,转换发生在Integer
类的longValue()
方法内。当您使用mapToLong(i -> i)
时,转换发生在包含 lambda 主体的合成方法中。当您使用mapToLong(Integer::intValue)
时,转换发生在运行时生成的ToLongFunction
中。在所有情况下,代码路径都将包含 i2l
@GauthamM 是的,但这对任何 JIT 编译器都没有挑战。它总是归结为读取Integer
的值字段并将其转换为long
值。以上是关于Stream api reduce方法在尝试对大数求和时返回负值[重复]的主要内容,如果未能解决你的问题,请参考以下文章
为啥不在 Stream API 中使用 reduce 来合并多个映射?