数字运算除以0一定会报错吗
在Java中进行数字类型运算时,容易有一种误解:进行除法运算时,如果除数为0则会在运行时会抛出java.lang.ArithmeticException: / by zero
的运行时异常。
但事实上并非如此,以double类型数据运算为例,看下面这段运算的结果:1
2
3
4
5
6
7
8
public void DoubleTest() {
double d1 = 10D / 0;
double d2 = -10D / 0;
double d3 = 0.0D / 0;
System.out.println("d1=" + d1 + ", d2=" + d2 + ", d3=" + d3); //输出结果:d1=Infinity, d2=-Infinity, d3=NaN
}
输出结果:d1=Infinity, d2=-Infinity, d3=NaN。
这里的Infinity
、-Infinity
和NaN
并不是字符串,而是double类型的常量,查看double类型对应的包装类的源码就可以看到。
1 | public final class Double extends Number implements Comparable<Double> { |
上面几个 double 常量的意思:
- POSITIVE_INFINITY(正无穷大),正数除以零得到正无穷。
- NEGATIVE_INFINITY(负无穷大),负数除以零得到负无穷。
- NaN(非数字),0除以0时得到非数字。
所以就会导致一个问题,如果一个对象的属性值是NaN,在通过JDBC将对象插入到数据库中时,因为NaN对数据库而言并不是一个有效数字,就会报错:java.lang.IllegalArgumentException: NaN
。如果使用了MyBatis,会看到有Error setting non null for parameter #xxx with JdbcType DOUBLE
这种异常。
NaN是什么
定义
NaN(Not a Number,非数)是计算机科学中数值数据类型的一个值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。
会返回NaN的运算
- 操作数中至少有一个是 NaN 的运算:
- 未定义的操作
- 下列除法运算:0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞
- 下列乘法运算:0×∞、0×-∞
- 下列加法运算:∞ + (−∞)、(−∞) + ∞
- 下列减法运算:∞ - ∞、(−∞) - (−∞)
- 产生复数结果的实数运算。例如:
- 对负数进行开方运算
- 对负数进行对数运算
- 对比-1小或比+1大的数进行反正弦或反余弦运算
Java中的NaN:
Java虚拟机在处理浮点数运算时,不会抛出任何运行时异常(这里所讲的是java语言中的异常,请勿与IEEE 754规范中的浮点异常相互混淆,IEEE 754的浮点异常是一种运算信号)。
如果一个操作产生溢出时,将会使用有符号的无穷大来表示;如果某个操作结果没有明确的数学定义的话,将会使用NaN值来表示,所有使用NaN值作为操作数的算术操作,结果都返回NaN。
Java中的Double和Float中都有isNaN
函数,可以用来判断一个数是不是NaN,其实现是通过 v != v 的方式,因为NaN是唯一与自己不相等的值,NaN与任何值都不相等。(和NaN不同,Infinity和自己比时相等的。)1
2
3public static boolean isNaN(float v) {
return (v != v);
}
还有一点需要注意:如果将一个double或float的NaN转换为整数类型T(T限于int或long类型之一),将会转化为int或long类型的0;而double类型的NaN值将按规定转换为float类型的NaN值。
1 |
|