fastjson 处理 double 的精度问题

Posted 牧码人 - blacksonny在路上

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fastjson 处理 double 的精度问题相关的知识,希望对你有一定的参考价值。

项目中使用 fastjson 来处理 json 格式,当前使用的版本为1.1.37。在和其它系统交互时,将一个json串传给了对方,原值为5.0,json 处理后格式为:{"dou", 5}; 结果对方处理该串报错了, 原因是他将串整理转成 Map ,在取值时强制转为了 Double ,因为拿到的值转化是 Integer 类型,强转肯定异常了。 简单的做法应该通过 Double.valueOf(value)  进行处理。但无奈合作方不愿意处理。 于是测试了下fastjson处理这个串时,通过以下做处理, 输出的结果为 {"dou", 5}。

JSONObject jsonObject = new JSONObject();
Double dou = new Double(5.0);
jsonObject.put("dou", dou);
System.out.println(JSON.toJSONString(jsonObject));

想要输出{"dou",5.0} 怎么办, 跟踪了下源码,发现在 DoubleSerializer 的 write 方法中,判断了结尾如果是.0 就截掉了。

doubleText = Double.toString(doubleValue);
if(doubleText.endsWith(".0")) {
    doubleText = doubleText.substring(0, doubleText.length() - 2);
}

那想要的格式怎么办,可以通过自定义 filter 方式实现,:

 ValueFilter filter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                if(value instanceof BigDecimal || value instanceof Double || value instanceof Float){
                    return new BigDecimal(value.toString());
                }
                return value;
            }
        };

String s  = JSON.toJSONString(jsonObject, filter, new SerializerFeature[0]);

以上可以完美解决。后来想有没有跟好的方法呢。 于是网上搜索了一下,大多数都是这种做法,并且有人认为这是一个bug,于是突然想有没有可能 wenshao 会处理一下,于是在 github 找到 fastjson 的最新版本 1.2.23。 先修改 pom 文件,然后运行。发现即使不处理也能输出了 {"dou",5.0} 。 于是 debug 进去原来对 DoubleSerializer 进行了重写,并在 write 方法中原来处理格式的地方修改为如下:

if (decimalFormat == null) {
    out.writeDouble(doubleValue, true);
} else {
    String doubleText = decimalFormat.format(doubleValue);
    out.write(doubleText);
}

//out SerializeWriter
String doubleText = Double.toString(doubleValue);
if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && doubleText.endsWith(".0")) {
    doubleText = doubleText.substring(0, doubleText.length() - 2);
}

即,以上粉色代码调用 SerializeWriter 的writeDouble 方法, 看绿色部分。 同时判断了 SerializerFeature.WriteNullNumberAsZero 和 结尾是否为 .0

就是通过这个解决了 double 精度的正常输出。  在使用 1.2.23时如果想输出{"dou", 5}, 可以通过设置 SerializerFeature.WriteNullNumberAsZero 实现。

System.out.println(JSON.toJSONString(jsonObject, SerializerFeature.WriteNullNumberAsZero));

啰嗦了这么,希望通过升级版本解决同样遇到这样问题的小伙伴。

以上是关于fastjson 处理 double 的精度问题的主要内容,如果未能解决你的问题,请参考以下文章

iOS - Json解析精度丢失处理(NSString, Double, Float)

float和double的区别 float和double5点区别

iOS数据解析精度丢失

double 转换long 丢失精度

FLOAT 和 DOUBLE区别

BigDecimal类处理高精度计算