
json 中的高精度数字(如 `"amount": 123345555789123495.38`)若被解析为 `double` 再转 `bigdecimal`,会因 `double` 二进制精度限制导致严重失真;正确做法是**跳过 `double` 中间表示,直接从原始 json 字符串构造 `bigdecimal`**。
在 Java 处理 JSON 数据时,若使用 Jackson 等库默认将数值字段反序列化为 Double(例如通过 ConcurrentHashMap
✅ 正确方案:绕过 double,保留原始 JSON 字符串形式。推荐两种实践方式:
方式一:使用 Jackson 的 JsonNode 显式读取为字符串
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);
String amountStr = rootNode.path("amount").asText(); // 确保未被转为 number
BigDecimal amount = new BigDecimal(amountStr).setScale(2, RoundingMode.HALF_UP);方式二:自定义反序列化器(推荐用于实体类)
public class AmountDeserializer extends JsonDeserializer{ @Override public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { // 强制按字符串读取,避免 double 解析 String text = p.getText(); return new BigDecimal(text).setScale(2, RoundingMode.HALF_UP); } } // 使用示例 public class Order { @JsonDeserialize(using = AmountDeserializer.class) private BigDecimal amount; }
⚠️ 注意事项:
- ❌ 避免 new BigDecimal(String.valueOf(doubleValue)):String.valueOf(1.23345555789123488E17) 仍基于已失真的 double,无法恢复原始精度;
- ✅ 始终优先从 JsonParser.getText() 或 JsonNode.asText() 获取原始字符串;
- ? 若业务要求严格金融精度,建议服务端统一以字符串格式传输金额字段(如 "amount": "123345555789123495.38"),并在 Schema 层面约束类型;
- ? setScale(2, RoundingMode.HALF_UP) 更符合金融四舍五入惯例(HALF_EVEN 虽标准但易引发业务理解偏差,需与财务规范对齐)。
总结:精度丢失根源不在 BigDecimal,而在 double 这一中间环节。只要确保 JSON 数字未经 double 解析、直接以字符串进入 BigDecimal 构造器,即可实现零精度损失的高保真转换。










