相信org.json包下的jsonObject有些人比较熟悉了,它是android原生的json解析类,先看下org.json 包的结构,比较简单:
今天在用这个对象注意到了这个问题:在对服务器返回来的JsonObject做解析时,我用JsonObject.getXXX()方法取返回值,之前没注意,log中经常抛warn类型的异常:JsonException.原来这是get这种方法均会抛出的异常:
public Object get(String name) throws JSONException {
Object result = nameValuePairs.get(name);
if (result == null) {
throw new JSONException("No value for " + name);
}
return result;
}
无论是getString(),getBoolean等方法,均会有类似上述异常抛出。而我要实现的功能是将jsonObject转化成实体bean,但是json中有值为null的情况(我需要将null转化成”“或者0),导致程序被try catch掉,不能继续转化。这是我的代码:
为了解决这个问题,我本着这个android原生的解析类作者不可能这么sb的想法,心想肯定有其他方法可以替代,很快就找到了opt方法,这是Json.opt() 的方法说明:
Returns the value mapped by {@code name}, or null if no such mapping exists.
意思是说如果没有匹配name的值的话,就会return null(注意,坑就在这里!)
我非常高兴找到了“解决办法”,于是就把代码全部换成了opt相关的方法,并有iterater寻找为null的值,如果为null,根据健的类型做相应的处理:
Iterator<String> keys = jsonObject.keys();
while (keys.hasNext()) {
String key = keys.next();
Object value = jsonObject.opt(key);
if(value==null) {
if("type".equals(key)) {
value = 0;
} else if("name".equals(key)) {
value = null;
}
}
}
结果通过log打印转化后的实体发现,type和name里面竟然还是null,根本没有得到转化!?于是我开启断点调试,发现通过opt返回的值竟然是”null” 而不是null。怎么会这样?原因之后解释。我通过进一步使用发现,使用JsonObject.optInt(),JsonObject.optLong()均没有问题,通过重载方法optInt(String name,int fallBack)可以指定默认值:
int value = jsonObject.optInt("type", 0);
如果type健的json值为null的话,value为0,但是如果使用optString(String name,String fallBack)就会有问题:
String name = jsonObject.optString("realName", "");
结果name的值为”null”而不是” ” 哎呀我就是纳闷了。决定晚上回去后再一探究竟。
回去后。。。。
这是optString的源码:
public String optString(String name, String fallback) {
Object object = opt(name);
String result = JSON.toString(object);
return result != null ? result : fallback;
}
调试进入后发现如果健为name的值为null的话,opt(name)这个返回的object直接为”null”,所以问题出现opt(name)这个方法里面
opt(String)源码:
public Object opt(String name) {
return nameValuePairs.get(name);
}
@Override public V get(Object key) {
/*
* This method is overridden to eliminate the need for a polymorphic
* invocation in superclass at the expense of code duplication.
*/
if (key == null) {
HashMapEntry<K, V> e = entryForNullKey;
if (e == null)
return null;
if (accessOrder)
makeTail((LinkedEntry<K, V>) e);
return e.value;
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) {
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
if (accessOrder)
makeTail((LinkedEntry<K, V>) e);
return e.value;
}
}
return null;
}
看出关键就在tab这个HashTabEntry,e.value返回了”null”,至于为啥,只有去看hashmap的原理了。。。
我在看stackoverflow找到了一种说法:
说是这是一个org.json的bug,确实,只有string会出现这个情况已经算bug了,解决方式是使用json.isNull()这个方法,通过这个判断值是否是null,如果是,则可以做处理:图中是直接将null返回,而我的功能就是返回空值,这就解决了这个坑了。。。
回过头来看之前所说的坑:opt(String name)说明:
Returns the value mapped by {@code name}, or null if no such mapping exists.
仔细想想,意思是说返回map中存在的值(通过健name),或者null,如果没有这个name所对应的值存在的话。。。意思说,只有name不存在这个情况,才会返回null。我去,这话说得。。。。
关于hashmap的原理,容小白的我懂了再补充,究竟为啥e里面就存了个”null”了?
如果要用json解析框架,就不会出现上述问题,但框架有框架的限制,自带的有比较高的灵活性,其中的优劣,只有看实际情况和个人取舍了,晚上跟一朋友争论用框架的好处与劣处,结果。。。开撕 了