Kotlin中BigDecimal转Double无精度丢失并输出指定小数位到JSON的方法
核心前提澄清
- 首先
Double类型本身不存储小数位数信息,0.0和0.000在Double的二进制存储里是完全相等的,不存在把BigDecimal转成自带三位小数属性的Double这种操作,你要的效果本质是JSON序列化阶段按指定小数位数输出数字格式。 - 直接用
toDouble()还存在精度丢失风险,比如BigDecimal("0.1")转Double本身就有精度误差,更不推荐先转Double再序列化。
解决方案(适配Vert.x + Jackson场景)
方案1:自定义Jackson的BigDecimal序列化器(最推荐,无精度损失)
不需要提前把BigDecimal转成Double,直接给Jackson配置自定义的BigDecimal序列化规则,让它序列化的时候固定输出3位小数:
- 先写自定义序列化类:
import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.ser.std.StdSerializer import java.math.BigDecimal import java.math.RoundingMode class FixedScaleBigDecimalSerializer(scale: Int = 3) : StdSerializer<BigDecimal>(BigDecimal::class.java) { private val targetScale = scale override fun serialize(value: BigDecimal?, gen: JsonGenerator, provider: SerializerProvider) { value?.let { // 先按四舍五入保留指定小数位,可根据需求修改RoundingMode val scaledValue = it.setScale(targetScale, RoundingMode.HALF_UP) // 直接输出为数字类型,不会转为字符串 gen.writeNumber(scaledValue) } ?: gen.writeNull() } }
- 给Vert.x的Jackson配置注册这个序列化器:
import io.vertx.core.json.jackson.DatabindCodec // 应用启动时执行一次即可 val objectMapper = DatabindCodec.mapper() objectMapper.registerModule( com.fasterxml.jackson.databind.module.SimpleModule() .addSerializer(BigDecimal::class.java, FixedScaleBigDecimalSerializer(3)) )
- 之后直接把BigDecimal对象放到
JsonObject里即可,不需要提前转Double,序列化后自动输出"amount": 0.000格式,同时完全避免精度损失。
方案2:针对单个字段配置序列化规则
如果不想全局改所有BigDecimal的序列化逻辑,只需要给特定字段加注解即可:
// 你的响应数据类 data class AmountResponse( @JsonSerialize(using = FixedScaleBigDecimalSerializer::class) val amount: BigDecimal )
方案3:临时适配方案
如果不想修改全局序列化配置,也可以在存入JsonObject前手动指定BigDecimal的精度:
val amount = BigDecimal("0.000") // 固定保留三位小数后存入 json.put("amount", amount.setScale(3, RoundingMode.HALF_UP))
避坑提示
- 不要提前用
BigDecimal.toDouble()做转换,Double本身的浮点精度问题会导致很多边界场景的数值误差,比如BigDecimal("0.29")转Double后会变成0.28999999999999998,反而不符合需求。 - 如果要求JSON输出的是字符串类型的
"0.000",只需要把上面序列化器里的gen.writeNumber改成gen.writeString(scaledValue.toPlainString())即可。
内容的提问来源于stack exchange,提问作者emee
相关产品推荐
相关产品推荐

