之前介绍了如何对 Map
进行遍历,里面提到了一个场景,就是将缓存到 Map
的数据存储到 JSONObject
中,我们知道,JSON
是一种与 Map
十分相似的数据交换格式,它同样采用了键值对的存储方式,那么现在就假设一个相反的场景,当我们需要将 JSON
中的数据缓存到本地时,也许遍历也不失为一种优雅的做法。
与 Map
的遍历相似,这个场景归根结底在于对 JSON
中 key
的遍历,因为只要拿到 key
,也就可以轻易拿到 value
。
JSONObject
的遍历也有多种实现方式:
Iterator.hasNext()
public static void jsonTraversal(JSONObject json) {
Iterator<String> it = json.keys();
while (it.hasNext()) {
String key = it.next();
Object value = json.opt(key);
// Do something...
}
}
JSONObject
的 keys()
方法会返回其所有 key
的 Set
集合的 Iterator
对象,因此我们可以直接对其迭代。
Iterator.forEachRemaining()
public static void jsonTraversal(JSONObject json) {
json.keys().forEachRemaining(key -> {
Object value = json.opt(key);
// Do something...
}
Java 8 之后 Iterator
也增加了 forEachRemaining()
方法,Lambda 的写法更加简洁。
JSONObject.names()
public static void jsonTraversal(JSONObject json) {
JSONArray array = json.names();
if (array != null) {
for (int i = 0; i < array.length(); i++) {
String key = array.optString(i);
Object value = json.opt(key);
// Do something...
}
}
}
JSONObject
中有个 names()
方法很有意思,它把 key
集合通过 JSONArray
也就是数组的形式返回,只需遍历这个数组将 key
值取出即可。
不过当 JSONObject
中不存在数据时,该方法会返回 null
,所以记得判空。
JSONObject.keySet()
public static void jsonTraversal(JSONObject json) {
for (String key : json.keySet()) {
Object value = json.opt(key);
// Do something...
}
}
我们知道 Map
中有 keySet()
方法,JSONObject
也有,返回的是一个包含所有 key
的 Set
集合,对其进行遍历即可。
同样,Java 8 上也可以用上 forEach()
:
public static void jsonTraversal(JSONObject json) {
json.keySet().forEach(key -> {
Object value = json.opt(key);
// Do something...
});
}
但是当在 Android 中使用 keySet()
时你会发现找不到该方法,查看源码可以看到其被限制了外部访问:
public class JSONObject {
/**
* Returns the set of {@code String} names in this object. The returned set
* is a view of the keys in this object. {@link Set#remove(Object)} will remove
* the corresponding mapping from this object and set iterator behaviour
* is undefined if this object is modified after it is returned.
*
* See {@link #keys()}.
*
* @hide.
*/
@UnsupportedAppUsage
@libcore.api.CorePlatformApi
public Set<String> keySet() {
return nameValuePairs.keySet();
}
}
而在普通的 Java 项目中引入最新的 org.json
库,是支持外部调用的,估计是 Android 官方出于某些原因考虑而将其限制了,又或者是 Android 源码中引入的是低版本 org.json
库的原因,因为我在最新的版本中看到的 entrySet()
方法,Android 源码中也没有:
public class JSONObject {
/**
* Get a set of entries of the JSONObject. These are raw values and may not
* match what is returned by the JSONObject get* and opt* functions. Modifying
* the returned EntrySet or the Entry objects contained therein will modify the
* backing JSONObject. This does not return a clone or a read-only view.
*
* Use with caution.
*
* @see Map#entrySet()
*
* @return An Entry Set
*/
protected Set<Entry<String, Object>> entrySet() {
return this.map.entrySet();
}
}
尽管这个方法是 protected
的。