最近在公司的价格计算需求中,因为精度的需要,使用到了BigDecimal。但是本人在使用BigDecimal踩到了一些坑,特此记录一下,并且希望能够帮助到后来者。
1、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类型初始化的构造方法!
2、BigDecimal的基本运算方式
java.math.BigDecimal 不是基本数据类型,而是一个封装类,所以我们平常对基本数据类型的操作例如:直接 +,-,*,\ 是行不通的,而是通过使用类的方法。 加法 :add()函数 减法 :subtract()函数 乘法 :multiply()函数 除法 :divide()函数 绝对值 :abs()函数
3、关于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));
输出结果: 
4、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
以上。
|