Java 8给了我们Math.addExact()来处理整数,而不是小数。
double
和BigDecimal
是否可能溢出?根据Double判断。MAX_VALUE和如何获得最大的BigDecimal值我想说答案是肯定的。
因此,为什么我们不为这些类型也设置Math.addExact()
呢?我们自己检查这一点的最可维护的方法是什么?
double
溢出到Infinity
和-Infinity
,不绕行。BigDecimal
不会溢出,周期,它只受限于您的计算机内存量。参见:如何获取最大的BigDecimal值
+
和.addExact
之间的唯一区别是它尝试检测是否发生溢出并抛出异常而不是包装。下面是源代码:
public static int addExact(int x, int y) {
int r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
if (((x ^ r) & (y ^ r)) < 0) {
throw new ArithmeticException("integer overflow");
}
return r;
}
如果你想检查是否发生了溢出,从某种意义上说,使用double
更简单,因为你可以简单地检查Double.POSITIVE_INFINITY
或Double.NEGATIVE_INFINITY
;在int
和long
的情况下,这是一个稍微复杂的问题,因为它并不总是一个固定值,但在另一个,这些可能是输入(例如Infinity + 10 = Infinity
,你可能不想在这种情况下抛出异常)。
由于所有这些原因(我们甚至还没有提到NaN
),这可能就是为什么这样的addExact
方法在JDK中不存在的原因。当然,您总是可以在自己的应用程序中将自己的实现添加到实用程序类中。
对于浮点数不需要addExact
函数的原因是,它不是绕行,而是溢出到Double.Infinity
。
Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY
是NaN,您还必须在更复杂的表达式的情况下检查NaN。这不仅更快,而且更容易阅读。而不是让Math.addExact(Math.addExact(x, y), z)
将3个双精度加在一起,你可以这样写:
double result = x + y + z;
if (Double.isInfinite(result) || Double.isNan(result)) throw ArithmeticException("overflow");
另一方面, BigDecimal
在这种情况下也会溢出并抛出相应的异常——尽管这在实践中不太可能发生。
double
请核对其他答案
BigDecimal
已经内置了addExact()
保护。BigDecimal
的许多算术运算方法(例如multiply
)包含对结果比例的检查:
private int checkScale(long val) {
int asInt = (int)val;
if (asInt != val) {
asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
BigInteger b;
if (intCompact != 0 &&
((b = intVal) == null || b.signum() != 0))
throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
}
return asInt;
}