java中用bigdecimal避免精度丢失的关键是四步闭环:字符串初始化、数据库直读直写、乘除显式设标度与舍入、json序列化启用writebigdecimalasplain。

Java 中用 BigDecimal 避免精度丢失,关键不是“用了没”,而是“怎么初始化、怎么运算、怎么流转”。浮点数误差一旦进入 BigDecimal,就再也洗不干净——它只会被“精确地错下去”。下面四点覆盖开发中最常踩的坑。
构造时别让 double 污染源头
这是 90% 精度问题的起点。new BigDecimal(0.1) 看似合理,实则把 double 的二进制残差原样封存,结果是 0.10000000000000000555...。
- ✅ 推荐:前端传字符串或后端字面量直接用
new BigDecimal("0.1") - ✅ 备选:已有 double 变量 d,用
BigDecimal.valueOf(d)(内部调用Double.toString(d),输出最短可读十进制) - ❌ 禁止:
new BigDecimal(d),无论 d 是 1.0 还是 19.99,底层已失真 - ⚠️ 注意:若 d 来自计算(如
a + b),valueOf()只能“干净呈现错误”,不能修复;应全程用 BigDecimal 运算
数据库交互必须绕过 double 中间层
数据库字段定义为 DECIMAL(18,2) 仅是第一步。JDBC 读写若经过 double,等于前功尽弃。
- ✅ 读取:用
resultSet.getBigDecimal("amount"),跳过 double 解析 - ✅ 写入:用
preparedStatement.setBigDecimal(1, amount),不转 double - ❌ 禁止:
resultSet.getDouble("amount")再转 BigDecimal,误差重演
加减乘除必须显式控制标度和舍入
加减法天然保精度(只要标度一致),但乘除会改变小数位数,不设限就会失控。
- ✅ 加减:
a.add(b)、a.subtract(b)可直接调用 - ✅ 乘法:优先用双参
multiply(BigDecimal, MathContext),例如a.multiply(b, new MathContext(10, RoundingMode.HALF_UP)) - ✅ 除法:必须指定标度与舍入模式,如
a.divide(b, 2, RoundingMode.HALF_EVEN)(银行家舍入,金融常用) - ❌ 禁止:
divide(BigDecimal)单参方法——除不尽直接抛ArithmeticException
序列化到 JSON 要防止格式变形
FastJSON 默认调用 toString(),会把 "1.0123" 输出为 1.0123(没问题),但把 "1.00" 输出为 1,前端解析后变成整数,业务逻辑崩塌。
- ✅ 正确做法:启用
SerializerFeature.WriteBigDecimalAsPlain - ✅ 示例:
JSON.toJSONString(obj, SerializerFeature.WriteBigDecimalAsPlain) - ✅ 原理:内部调用
toPlainString(),保留原始小数位,禁用科学计数法
不复杂但容易忽略:从字符串构造、绕过 double 流转、乘除带舍入、序列化保格式——这四步闭环,才能真正守住精度底线。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











