如何防止Java代码中的整数溢出?

2022-09-01 10:37:30

可能的重复:
如何检查在Java中相乘两个数字是否会导致溢出?

假设我有一个Java类方法,它使用和操作。*+

int foo(int a, int b) {
  ... // some calculations with + and * 
}

如何确保没有溢出?foo

我想我可以使用或用“包装器”替换所有+和*,例如:BigDecimal

int sum(int a, int b) {
   int c = a + b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

int prod(int a, int b) {
   int c = a * b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

有没有更好的方法来确保Java方法中不会发生溢出?int


答案 1

检查溢出的一种方法是将操作数提升为更大的类型(是原始操作数位长度的两倍),然后执行操作,然后查看结果值对于原始类型是否太大,例如

int sum(int a, int b) {
    long r = (long)a + b;
    if (r >>> 32 != 0) {    // no sign extension
        throw new MyOverflowException(a, b);
    }
    return (int)r;
}

如果您的原始类型是 ,则必须用作较大的类型。longBigInteger


答案 2

从工程角度来看,这是一个难题。

安全编码网站建议:

  • 使用前提条件;即范围检查输入,以便溢出是不可能的,
  • 使用下一个较大的基元整数类型执行每个单独的算术运算,并显式检查溢出,或者
  • 使用 BigInteger。

这篇 Dr Dobbs 文章建议创建一个原始算术方法库,这些方法使用显式溢出检查执行每个原始运算。(您可以将其视为上述项目符号点 #2 的实现。但作者更进一步,建议你使用字节码重写来替换算术字节码,并调用包含溢出检查的等效方法。

遗憾的是,无法在 Java 中以本机方式启用溢出检查。(但这同样适用于许多其他语言;例如C,C++...