java中BigDecimal 讲解
BigDecimal讲解
前言
在 Java 开发中,涉及到金额计算、财务系统、电商报价等对数字精度要求极高的场景时,double 和 float 往往会成为制造 Bug 的罪魁祸首。
此时,就会使用这个类 —— BigDecimal。
为什么不能用 double 算钱?
代码如下:
1 | System.out.println(0.1 + 0.2); |
原因解析: 计算机底层使用二进制表示浮点数,而许多十进制小数(如 0.1)在二进制中是无限循环小数。double 会在某一位截断,从而导致精度丢失。在商业计算中,差一分钱也是极其严重的生产事故。
为了解决这个问题,Java 提供了 java.math.BigDecimal,专用于高精度计算。
一、 创建BigDecimal对象
创建 BigDecimal 对象时,最容易踩进“精度丢失”的二次陷阱。
1.1 错误用法
1 | BigDecimal bad = new BigDecimal(0.1); |
原因:传入的 0.1 已经是 double 类型,在传参前就已经丢失精度了。
1.2 正确推荐用法
1 | // 推荐 1:使用字符串构造(最安全、最常用) |
二、 核心运算:加减乘除
BigDecimal 是一个对象,不可变(Immutable),所以不能使用 + - * / 操作符,必须调用对应的方法,并且每次运算都会返回一个新的对象。
1 | BigDecimal a = new BigDecimal("10.0"); |
三、 舍入模式 (RoundingMode)
在除法或格式化输出时,我们通常需要保留小数位数。RoundingMode 枚举类提供了多种规则,最常用的有:
RoundingMode.HALF_UP:四舍五入(最常用,如 2.35 保留一位 -> 2.4)。RoundingMode.HALF_DOWN:五舍六入(遇到 5 往下舍弃)。RoundingMode.UP:向上取整(只要有小数就进位)。RoundingMode.DOWN:向下取整(直接截断尾数,不进位)。
四、 比较大小:慎用 equals
在对比两个 BigDecimal 的大小时,绝对不要轻易使用 equals(),而应该使用 compareTo()。
Java
1 | BigDecimal x = new BigDecimal("1.0"); |
总结
在 Java 中,金额、财务等高精度计算严禁使用 double 或 float,因其存在二进制浮点精度丢失。
必须使用 BigDecimal,创建时推荐字符串构造(new BigDecimal(“0.1”))或 valueOf,避免传入 double。
运算只能调用 add()、subtract()、multiply()、divide() 方法,除法必须指定小数位数和 RoundingMode(常用 HALF_UP)。
比较大小只能用 compareTo(),不要用 equals(),因为 equals 会同时比较精度 scale。