最近在開發(fā)的過程中遇到一個問題碍拆,服務(wù)端返回了一個JSON對象,在用JSON庫解析的時候出現(xiàn)了一個詭異的問題
服務(wù)端返回的原始JSON是
{
"value": "15493409528126467"
}
在程序中直接調(diào)用JSON中的方法
jsonObject.optLong("value");
打印的日志如下
origin value=15493409528126467
parse value=15493409528126468
通過JSON的方法取到的結(jié)果出現(xiàn)了不一致的情況瓮孙。應(yīng)該是轉(zhuǎn)換的時候精度出現(xiàn)了損失赃阀,一步一步跟到內(nèi)部的實現(xiàn)方法,先看optLong()
public long optLong(String name) {
return optLong(name, 0L);
}
這里調(diào)用了兩個參數(shù)的optLong()方法钾菊,在不傳默認值的時候如果出錯的話這個方法會返回0溃槐。再往里跟匣砖,這個方法內(nèi)部調(diào)用了JSON.toLong()方法。
public long optLong(String name, long fallback) {
Object object = opt(name);
Long result = JSON.toLong(object);
return result != null ? result : fallback;
}
接著向里面走
static Long toLong(Object value) {
if (value instanceof Long) {
return (Long) value;
} else if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof String) {
try {
return (long) Double.parseDouble((String) value);
} catch (NumberFormatException ignored) {
}
}
return null;
}
看來問題是出在這里了昏滴,當輸入的參數(shù)為String的時候猴鲫,toLong()方法會使用Double.parseDouble()方法解析,而我們知道double的精度是會有損失的谣殊,在Google的文檔上有這么一句話
When the requested type is a long, other Number types will be coerced using longValue. Strings that can be coerced using valueOf(String) will be, and then cast to long. This two-step conversion is lossy for very large values. For example, the string "9223372036854775806" yields the long 9223372036854775807.
在取非常大的數(shù)字的時候拂共,會先轉(zhuǎn)換成String,再通過parseDouble()方法轉(zhuǎn)成long姻几,這期間就造成了精度損失宜狐。
解決方法
先得到String類型的值,再將String轉(zhuǎn)成long
String str = jsonObject.optString("value");
long result = Long.valueOf(str);
這樣就可以正確的取到值了鲜棠,Long.valueOf()內(nèi)部實現(xiàn)調(diào)用了BigInteger中的方法肌厨,這樣就能保證結(jié)果正確了培慌。