我們知道數值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後,保持精度的例子:
作者:張人傑 某互聯網公司架構師