java浮点数精度问题源于ieee 754标准,并非bug;应选用bigdecimal(字符串或valueof构造)、显式设置divide精度与舍入模式、用compareto而非equals比较数值、高吞吐场景可采用整数放大法。

Java 中浮点数计算出现 0.1 + 0.2 = 0.30000000000000004 这类结果,不是 bug,而是 IEEE 754 二进制浮点表示的必然现象。真正的问题在于:你是否在该用高精度的地方用了 double。提升精度的关键不是“修 float”,而是选对工具、用对方式。
BigDecimal 构造必须用字符串或 valueOf
这是最常踩的坑。直接传 double 给 BigDecimal 构造器,等于把已有误差原封不动带进去:
-
❌ 错误写法:
new BigDecimal(0.1)→ 实际存储的是0.10000000000000000555... -
✅ 正确写法(推荐):
new BigDecimal("0.1")—— 字符串无转换失真 -
✅ 正确写法(兼容已有 double 变量):
BigDecimal.valueOf(0.1)—— 底层调用Double.toString(),规避了二进制截断
除法必须指定精度和舍入模式
BigDecimal 的 divide() 方法若不设参数,遇到 1 ÷ 3 这类无限小数会直接抛 ArithmeticException。生产环境务必显式控制:
- 保留 2 位小数、四舍五入:
a.divide(b, 2, RoundingMode.HALF_UP) - 金融常用银行家舍入(减少统计偏差):
RoundingMode.HALF_EVEN - 避免用已废弃的
BigDecimal.ROUND_HALF_UP(JDK 9+ 已标记过时)
比较与相等判断不能用 equals()
BigDecimal 的 equals() 会同时比较数值和 scale(小数位数),导致 new BigDecimal("1.0").equals(new BigDecimal("1")) 返回 false:
- 判断数值是否相等 → 用
compareTo():a.compareTo(b) == 0 - 判断是否为零 → 用
signum() == 0或compareTo(BigDecimal.ZERO) == 0 - 需要严格语义相等(值+精度都一致)才用
equals(),如缓存 key 场景
整数放大法适合高性能批量计算
当系统吞吐量极高、且业务允许固定小数位(如金额单位为“分”),整数运算是零开销方案:
- 将元转为分:
long cents = Math.round(amount * 100); - 全程 long 运算,无对象创建、无 GC 压力
- 输出前再转回:
double yuan = cents / 100.0;(注意除法仍用 double,仅用于展示) - ⚠️ 注意溢出:
long最大值约 9×10¹⁸,对应 9×10¹⁶ 元,一般业务足够;超量场景改用BigInteger
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











