IntStream.sum()异常处理

Tin*_*nki 1 java java-8

为什么IntStream.sum()返回一个int值?这是一些概念上的错误吗?从示例数组创建流时:

int A[] = {2^31-5, 2, 2, 2};
Run Code Online (Sandbox Code Playgroud)

所有元素的总和超过最大整数值,但不会抛出异常.有人知道如何预防这种情况吗?

Stu*_*rks 8

默认情况下,如果发生溢出,Java中的积分算术不会抛出任何异常.溢出操作被截断为低位32位int,64位用于long.

如果要为溢出条件抛出异常,可以使用类中的"完全"函数族java.lang.Math:

  • addExact
  • decrementExact
  • incrementExact
  • multiplyExact
  • negateExact
  • subtractExact
  • toIntExact

这些被定义为与普通的算术运算相同int,long除了它们抛出ArithmeticException溢出而不是截断结果.

使用流,您的示例将如下所示:

int a[] = { Integer.MAX_VALUE - 5, 2, 2, 2 };
int sum = Arrays.stream(a).reduce(0, Math::addExact);
Run Code Online (Sandbox Code Playgroud)

这将抛出ArithmeticException.

(注意你的例子是书面使用2^31-5,它是一个有效的表达式,就像^XOR运算符一样.结果是24当然不会溢出.)


Hol*_*ger 7

行为与int在循环中求和时得到的行为相匹配.有多种方法可以处理溢出,所有这些都是一般适用性和性能之间的权衡,因为API将/应该使用哪一个并不明显,所以选择了Java开发人员通常所知的那个. .

如果要使用更大的数据类型求和,可以使用其中任何一种

long sumL=IntStream.of(A).asLongStream().sum();// may still overflow
Run Code Online (Sandbox Code Playgroud)

要么

BigInteger sum = IntStream.of(A).mapToObj(BigInteger::valueOf)
                          .reduce(BigInteger.ZERO, BigInteger::add);// might be slower
Run Code Online (Sandbox Code Playgroud)

如果你想抛出行为,你可以使用

int sum=IntStream.of(A).reduce(0, (a,b)->{
    int c=a+b;
    if(a>0? b>0 && c<0: b<0&& c>0)
        throw new ArithmeticException("overflow");
    return c;
});
Run Code Online (Sandbox Code Playgroud)

或者,更简单(整合Stuart Marks的解决方案)

int sum=IntStream.of(A).reduce(0, Math::addExact);
Run Code Online (Sandbox Code Playgroud)