问题

先看一个例子:

    public static void main(String[] args){
        BigDecimal num1 = new BigDecimal(3);
        BigDecimal num2 = new BigDecimal(7);
        BigDecimal num3 = num1.divide(num2).setScale(2);
        System.out.println(num3);
    }

这段代码运行过程中会抛出一个异常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
意思大概是运算异常,没有可精确表示的十进制结果。

原因

因为结果除不尽,所以在 divide 的时候已经抛出了该异常,并不会进行保留两位小数的运算。

解决方案

在使用BigDecimal进行除法运算时,最好使用divide的重载方法

    /**
    * divisor 除数
    * scale 保留几位小数
    * roundingMode 舍入模式
    */
    public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
        return divide(divisor, scale, roundingMode.oldMode);
    }

所以写成以下方式就没问题了

    public static void main(String[] args){
        BigDecimal num1 = new BigDecimal(3);
        BigDecimal num2 = new BigDecimal(7);
        BigDecimal num3 = num1.divide(num2,2,BigDecimal.ROUND_HALF_DOWN);
        System.out.println(num3);
    }

备注:关于RoundingMode的几种模式

  • ROUND_UP
    向远离零的方向舍入。向外取整模式
  • ROUND_DOWN
    向接近零的方向舍入。向内取整模式
  • ROUND_CEILING
    向正无穷大的方向舍入。向上取整模式
  • ROUND_FLOOR
    向负无穷大的方向舍入。向下取整模式
  • ROUND_HALF_UP
    向“最接近的”整数舍入。四舍五入模式
  • ROUND_HALF_DOWN
    向“最接近的”整数舍入。五舍六入模式
  • ROUND_HALF_EVEN
    若(舍入位大于5)或者(舍入位等于5且前一位为奇数),则对舍入部分的前一位数字加1;若(舍入位小于5)或者(舍入位等于5且前一位为偶数),则直接舍弃。即为银行家舍入模式
  • ROUND_UNNECESSARY
    具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException