我们知道数值2.9传递给一个double型的变量a时,a就变成了2.899999999999999911182158029987476766109466552734375,而不是2.9。所以,也有了double值比较是否相等时需要比较一个范围的if判断方式。
而在金融系统中,数值计算往往需要精确的计算和表达,这就在java系统中引入了BigDecimal数据类型,但是普通的程序员会记得在java中使用BigDecimal,而往往忽视在json接口开发中,java对象转换成json,再由json转换成java对象时的精度丢失。
因为:java转换成json对象时,BigDecimal就变成了double表达,结果是{"value":2.899999999999999911182158029987476766109466552734375};(这一步丢失了精度)
而再由json转换成java时,调用的是new BigDecimal(double)方法,而不是new BigDecimal(String)方法;因此,数据就在这又丢失了精度(原始数据为2.899999999999999911182158029987476766109466552734375,而转换后成了2.9)。
下图是精度丢失的例子,转换使用的是fasterxml.jackson:
为此,在所有的json接口编码中,我们需要规范数值的传递必须使用BigDecimal的String方式,也就有了我的架构代码中的下方这个标注处理类:
package com.zhrenjie04.alex.core;
import java.io.IOException;
import java.math.BigDecimal;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* 用于@JsonSerialize标注序列化BigDecimal为字符串
* 用法:@JsonSerialize(using=AlexBigDecimalSerializer.class)
* @author Alex.Zhang 作者:张人杰
* 使用、引用,请保留作者信息
*/
public class AlexBigDecimalSerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
if(value!=null) {
gen.writeString(value.toString());
}else {
gen.writeNull();
}
}
}
用法也很简单:
public class BigDecimalToJsonExample {
@JsonSerialize(using=AlexBigDecimalSerializer.class)
private BigDecimal value;
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public static void main(String[] args) {
BigDecimal d=new BigDecimal("2.9");
BigDecimalToJsonExample example=new BigDecimalToJsonExample();
example.setValue(d);
String s=JsonUtil.stringify(example);
System.out.println(s);
example=JsonUtil.parse(s, BigDecimalToJsonExample.class);
System.out.println(example.getValue());
}
}
这样,在BigDecimal的数据转换后,就变成了:{"value":"2.9"},再由json转换为BigDecimal时调用的就是new BigDecimal(String),这就保证了数值精度的不丢失。下面是使用AlexBigDecimalSerializer后,保持精度的例子:
作者:张人杰 某互联网公司架构师