我们在日常开发中, 有很多时候会遇到小数(
场景
- 商品a价格是 0.1, 商品b 价格是 0.2, 用户买了这两个商品, 付款时, 订单总金额是 0.3, 如果用
double 类型做计算, 将会得到结果0.30000000000000004 , 前端如果拿来展示总金额, 用户肯定就蒙圈了, 这显然不是我们想要的. - 那么如何解决呢?
Java 给我们提供了专门解决这个问题的类BigDecimal .
double a = 0.1; double b = 0.2; double c = a + b; System.out.println(c); // 0.30000000000000004
BigDecimal 使用
创建 BigDecimal 对象
创建对象一共有
// 1 入参是 double BigDecimal a = new BigDecimal(0.3); // 2 入参是 String BigDecimal b = new BigDecimal("0.3"); // 3 静态方法, 入参是 double BigDecimal c = BigDecimal.valueOf(0.3);
计算操作
- 公用代码
double a = 0.1; double b = 0.2; BigDecimal a1 = BigDecimal.valueOf(a); BigDecimal b1 = new BigDecimal(Double.toString(b));
1. 加法 add
- 这就很好的解决了上面场景中出现的问题
BigDecimal c1 = a1.add(b1); System.out.println(c1); // 0.3
2. 减法 subtract
BigDecimal c2 = a1.subtract(b1); // 减法 System.out.println(c2); // -0.1
3. 乘法
BigDecimal c3 = a1.multiply(b1); // 乘法 System.out.println(c3); // 0.02
4. 除法
BigDecimal c4 = a1.divide(b1); // 除法 0.1 / 0.3, 无法除尽, 报错. System.out.println(c4); // 0.5 BigDecimal c5 = a1.divide(c1); // 除法 System.out.println(c5); // 0.1 / 0.3, 无法除尽, 报错. c5 = a1.divide(c1, 2, RoundingMode.HALF_UP); // 除法 0.1 / 0.3 四舍五入 System.out.println(c5); // 0.5
注意:
- BigDecimal 进行除法计算时, 强烈建议使用指定保留小数倍数和舍入模式这个方法, 这样可以避免除不尽造成的异常.
/** * 参数1: 除数 * 参数2: 保留小数的位数 * 参数3: 舍入模式 */ public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
5. 保留小数和舍入模式
设置保留小数和舍入模式
BigDecimal price = new BigDecimal("9.936"); price = price.setScale(2, RoundingMode.HALF_UP); // 2位, 四舍五入 System.out.println(price); // 9.94
6. BigDecimal 转化为 double
double value = c4.doubleValue();
总结
使用
不建议 使用入参是double 的构造器, 因为它仍然存在精度问题.强烈建议 使用入参是string 的构造器, 或者使用静态方法valueOf 创建对象, 才能保证精度.- 使用
BigDecimal 做除法 时, 必须要使用divide(BigDecimal divisor, int scale, RoundingMode roundingMode) , 防止除不尽造成异常.