android使用JSON遇到的坑(1)

最近在开发的过程中遇到一个问题,服务端返回了一个JSON对象,在用JSON库解析的时候出现了一个诡异的问题
服务端返回的原始JSON是

{
    "value": "15493409528126467"
}

在程序中直接调用JSON中的方法

jsonObject.optLong("value");

打印的日志如下

origin value=15493409528126467
parse value=15493409528126468

通过JSON的方法取到的结果出现了不一致的情况。应该是转换的时候精度出现了损失,一步一步跟到内部的实现方法,先看optLong()

public long optLong(String name) {
    return optLong(name, 0L);
}

这里调用了两个参数的optLong()方法,在不传默认值的时候如果出错的话这个方法会返回0。再往里跟,这个方法内部调用了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;
}

看来问题是出在这里了,当输入的参数为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.

在取非常大的数字的时候,会先转换成String,再通过parseDouble()方法转成long,这期间就造成了精度损失。

解决方法

先得到String类型的值,再将String转成long

String str = jsonObject.optString("value");
long result = Long.valueOf(str);

这样就可以正确的取到值了,Long.valueOf()内部实现调用了BigInteger中的方法,这样就能保证结果正确了。

IT文库 » android使用JSON遇到的坑(1)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址