关于BigDecimal日常使用中的一些注意点
最近在公司的价格计算需求中,因为精度的需要,使用到了BigDecimal。但是本人在使用BigDecimal踩到了一些坑,特此记录一下,并且希望能够帮助到后来者。
BigDecimal的初始化赋值
关于BigDecimal的初始化问题,我这里强烈建议大家采用String类型对其进行数据初始化,因为采用基本数据类型初始化再进行运算会出现很奇怪的运算结果:
//采用String进行初始化赋值
BigDecimal num = new BigDecimal("0.005");
BigDecimal price = new BigDecimal("0.002");
//使用基本数据类型进行赋值
BigDecimal num2 = new BigDecimal(0.005);
BigDecimal price2 = new BigDecimal(0.002);
System.out.println("采用String类型初始化BigDecimal:"+price.multiply(num));
System.out.println("采用基本数据类型初始化BigDecimal:"+price2.multiply(num2));
运行结果:
下面给大家贴下采用不同类型初始化值进行运算产生的差异:
造成这样的原因为:不是所有的浮点数都能够被精确的表示成一个double 类型值,有些浮点数值不能够被精确的表示成 double 类型值,因此它会被表示成与它最接近的 double 类型的值。而BigDecimal无论是使用int类型,还是double类型,计算结果都是不准确的。
必须使用采用String类型初始化的构造方法!
BigDecimal的基本运算方式
java.math.BigDecimal 不是基本数据类型,而是一个封装类,所以我们平常对基本数据类型的操作例如:直接 +,-,*,\ 是行不通的,而是通过使用类的方法。
加法 :add()函数
减法 :subtract()函数
乘法 :multiply()函数
除法 :divide()函数
绝对值 :abs()函数
关于BigDecimal出现0 E-8等情况
问题的原因出在:BigDecimal的值小数点位数达到8位,Java自动采用科学计数法进行统计。
//采用String进行初始化赋值
BigDecimal num = new BigDecimal("0.005");//三位小数点
BigDecimal price = new BigDecimal("0.0002");
BigDecimal num2 = new BigDecimal("0.0005");//四位小数点
System.out.println("七位小数点的运算:"+price.multiply(num));
System.out.println("八位小数点的运算:"+price.multiply(num2));
输出结果:
BigDecimal判断:是否为空,是否为0
我需要从实体类从获取price单价,num数量(都为BigDecimal类型),并且在后台对其进行校验,本人在一开始是使用 ( == 0 || equals.(null))对两个参数进行校验,但是发现是无效的。
无效原因:
1、使用 " == " 进行比较
首先BigDecimal不是基本类型,它只是把你的数值(基本类型)封装到了intCompact(Long类型)这个属性中,是对象类型,而只能比较基本类型,所以用“”肯定是不对的。
2、equals()
再说BigDecimal的equals()方法,此方法被其重写了,但并不是像String类一样重写为==,而是
@Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflated().equals(xDec.inflated());
}
从源码中可以看到有一个判断scale 值是否相等,scale 这个值是BigDecimal的私有属性,表示BigDecimal小数点位数,所以equals判断两个值是否相等,会先判断这两个数值是否小数点位数是否相等,然后在判断值是否相等。
3、compareTo()方法
采用BigDecimal类的比较方法:compareTo()方法,和BigDecimal.ZERO
此固有属性scale为0,故判断结果是否为0,结果为0则相等,否则不等
price1.compareTo(BigDecimal.ZERO)==0
以上。