如何防止Java代码中的整数溢出?
可能重复:
如何检查Java中的两个数字相乘是否会导致溢出?
假设我有一个Java类方法,它使用*
和+
操作。
int foo(int a,int b){ ... //用+和*进行一些计算 }
如何确保foo
中没有溢出?
我想我可以使用BigDecimal
或用“wrappers”替换所有+和*,如:
int sum(int a,int b){ int c = a + b; if(a> 0 && b> 0 && c 0 && b> 0 && c <0) 抛出新的MyOverfowException(a,b) 返回c; }
有没有更好的方法来确保Java方法中没有发生int
溢出?
从工程角度来看,这是一个难题。
安全编码站点建议:
- 使用先决条件; 即范围检查输入,以便不可能溢出,
- 使用下一个较大的原始整数类型执行每个单独的算术运算并显式检查溢出,或
- 使用BigInteger。
这篇Dobbs博士的文章建议创建一个原始算术方法库,它使用显式溢出检查来执行每个基本操作。 (您可以将其视为上面第2点要点的实现。)但作者更进一步建议您使用字节码重写来替换算术字节码,并调用包含溢出检查的等效方法。
不幸的是,没有办法在Java中本机启用溢出检查。 (但同样适用于许多其他语言;例如C,C ++ ……)
检查溢出的一种方法是将操作数提升为更大的类型(原始操作数位长度的两倍)然后执行操作,然后查看结果值是否对于原始类型来说太大,例如
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; }
如果您的原始类型很long
,则必须使用BigInteger
作为较大的类型。
总和:检查b是否大于您可以存储在int中的最大值的差减去a的值。 如果a和/或b可以是负数,则必须(i)注意不要为差异检查获得溢出并且(ii)对最小值执行类似的检查。
产品:这更难。 我将整数分成两个半长整数(即如果int是32位,使用位掩码和移位将其分成两个16位数)。 然后进行乘法运算,然后查看结果是否适合32位。
在你不想简单地为临时结果花费long
的条件下的一切。
假设a和b都是正数或负数,如果a + b的符号与a和b的符号不相等,则发生溢出。 您可以使用此规则判断是否发生溢出并抛出exception。 当你发现这种情况时,你可以按照之前答案中提到的方法处理它。 另一种方法是使用不会溢出的最大范围类型进行操作。 您可以使用long来执行Integers之间的操作。