You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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位小数:

  1. 先写自定义序列化类:
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()
    }
}
  1. 给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))
)
  1. 之后直接把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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 16:45:04