关于BigDecimal

Home / Code / Body Text

BigDecimal

问题

  今天工作的时候碰到了前端录入整数时可以正常运行,但是录入小数时会出现异常。一顿寻找后发现是在Action方法中将BigDecimal的精度定义为了0,所以才会出现精度异常。解决办法是将精度设置为2并且后边多出的位数直接舍弃。

异常为:

java.lang.ArithmeticException:Rounding necessary

导致异常的代码:

prpLcheckDuty.setIndemnityDutyRate(prpLcheckDuty.getIndemnityDutyRate().setScale(0));

修改后的代码:

prpLcheckDuty.setIndemnityDutyRate(prpLcheckDuty.getIndemnityDutyRate().setScale(2,BigDecimal.ROUND_DOWN))

总结了一下在使用BigDecimal数据类型进行计算时可能会出现java.lang.ArithmeticException的问题:
  1. 当除数为0时,这种情况比较常见,所以我们在进行除法运算之前先判断下除数是否为0。
  2. 如果运算的结果是无限循环的小数,并且在除的时候没有对结果设置精确的位数,这时就会抛出异常,这种情况比较容易被忽视,抛出异常后一般都会考虑是否为0,因此,要特别注意。
 3. 当我们设置了结果的舍入模式是:ROUND_UNNECESSARY模式时,如果确保了计算的结果是精确的,则不会抛出异常,否则,就会抛出ArithmeticException异常。
  4. 设置的精度小于录入的位数时可能会出现java.long.ArithmeticException,如果设置的精度大于录入的位数时,数字的末尾会自动用0来补位。

设置的精度小于录入位数实例代码:

public class Test {
    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal(98.01111);
        System.out.println(bigDecimal1.setScale(2));
        BigDecimal bigDecimal2 = new BigDecimal("98.01111");
        System.out.println(bigDecimal2.setScale(2));
    }
}

运行结果如下:
2230008287.png

在进行金额等比较敏感的数据运算时,我们可以用BigDecimal类型进行运算:java.math.BigDecimal,此类为我们提供了四种构造方法,我们常用的两种是:BigDecimal(double) 和 BigDecimal(String)。
例:

System.out.println(new BigDecimal(1.01));
System.out.println(new BigDecimal("1.01"));

输出结果为:
1.0100000000000000088817841970012523233890533447265625
1.01

解决使用BigDecimal类型,传入double型值的时候,精确度乱掉问题:

API解释:

  此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double (或者说对于该情况,不能表示为任何有限长度的二进制小数),这样,传入 到构造方法的值不会正好等于0.1(虽然表面上等于该值)

  另一方面,String 构造方法是完全可预知的:写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。

  当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为String。要获取该结果,请使用 static valueOf(double) 方法。

解决方案:

传入double类型值时,调用下toString方法。

BigDecimal一些常用的方法

含义方法
add(BigDecimal对象)
subtract (BigDecimal对象)
multiply (BigDecimal对象)
divide (BigDecimal对象)
除(四舍五入)divide (BigDecimal对象,精确几位,舍入模式)

舍入模式:

含义方法
进一法BigDecimal.ROUND_UP
RoundingMode.UP
去尾法BigDecimal.ROUND_FLOOR
RoundingMode.FLOOR
四舍五入BigDecimal.ROUND_HALF_UP
RoundingMode.HALF_UP

注意事项:
  1. BigDecimal是用来进行精确计算的。
  2. 创建BigDecimal的对象,构造方法使用参数类型为字符串的。
  3. 四则运算中的除法,如果除不尽请使用divide的三个参数的方法。

No Tags
Reward
Comments Section
头像