Java如何无大量if语句解析含多异构条目的JSON文件?
异构JSON数组解析优化方案及Map列表转换问题
问题背景
假设我们有如下格式的JSON数组文件:
[ { "id": "_oG_iTxP1pIC", "volumeInfo": { "title": "Flowers For Algernon", "description": "A description ", "pageCount": 321 }, "saleInfo": { "isEbook": true, "listPrice": { "amount": 7.99, "currencyCode": "EUR" }, "retailPrice": { "amount": 5.75, "currencyCode": "EUR" } } }, {...}, {...}, ... ]
但并非所有条目格式一致,部分字段可能缺失(例如saleInfo对象可能完全不存在)。
目前采用大量if判断字段是否存在的方式解析,将信息存入Book对象的ArrayList中,核心代码如下:
if (book.has("id")) id = book.getString("id"); if (book.has("volumeInfo")) volumeInfo = book.getJSONObject("volumeInfo"); if (volumeInfo.has("title")) title = volumeInfo.getString("title"); if (volumeInfo.has("description")) description = volumeInfo.getString("description"); if (volumeInfo.has("pageCount")) pageCount = volumeInfo.getInt("pageCount"); if (book.has("saleInfo")) saleInfo = book.getJSONObject("saleInfo"); if (saleInfo.has("isEbook")) isEbook = saleInfo.getBoolean("isEbook"); if (saleInfo.has("listPrice")) listPrice = saleInfo.getJSONObject("listPrice"); if (listPrice != null){ if (listPrice.has("amount")) listPriceAmmount = listPrice.getFloat("amount"); if (listPrice.has("currencyCode")) listPricecurrencyCode = listPrice.getString("currencyCode"); } if (saleInfo.has("retailPrice")) retailPrice = saleInfo.getJSONObject("retailPrice"); if (retailPrice != null){ if (retailPrice.has("amount")) retailPriceAmmount = retailPrice.getFloat("amount"); if (retailPrice.has("currencyCode")) retailPricecurrencyCode = retailPrice.getString("currencyCode"); } this.listOfBooks.setNewBook(new Book(id, title, description, pageCount, listPriceAmount, listPriceCurrencyCode, retailPriceAmount, retailPriceCurrencyCode));
Book类定义如下:
public class Book { private String id, selfLink, title, publisher, publishedDate, description, language, listPriceCurrencyCode, retailPriceCurrencyCode; public JSONArray authors, industryIdentifiers, categories; private int pageCount; private double listPriceAmount, retailPriceAmount; Book( String id, String selfLink, String title, JSONArray authors, String publisher, String publishedDate, JSONArray industryIdentifiers, String description, int pageCount, JSONArray categories, String language, double listPriceAmount, String listPriceCurrencyCode, double retailPriceAmount, String retailPriceCurrencyCode ) { this.setId(id); this.setSelfLink(selfLink); this.setTitle(title); this.setAuthors(authors); this.setPublisher(publisher); this.setPublishedDate(publishedDate); this.setIndustryIdentifiers(industryIdentifiers); this.setDescription(description); this.setPageCount(pageCount); this.setCategories(categories); this.setLanguage(language); this.setListPriceAmount(listPriceAmount); this.setListPriceCurrencyCode(listPriceCurrencyCode); this.setRetailPriceAmount(retailPriceAmount); this.setRetailPriceCurrencyCode(retailPriceCurrencyCode); } }
疑问:
- 这种大量
if判断的解析方式不够优雅,有没有更好的方法解析此类含大量异构条目的JSON文件? - 能否将整个JSON数组转换为
Map列表?
解决方案
一、使用JSON序列化框架替代手动判断
手动写if判断不仅冗余,还容易出错,推荐使用成熟的JSON序列化框架(如Gson、Jackson)来自动处理字段缺失的情况,框架会自动忽略不存在的字段,无需手动判断。
1. 使用Gson实现解析
首先引入Gson依赖,然后修改Book类:
- 添加无参构造方法(Gson序列化/反序列化必需)
- 对可能缺失的基本类型字段,改用包装类(比如
Integer代替int,Double代替double),避免字段缺失时出现默认值歧义 - 若类字段名与JSON字段名不一致,可添加
@SerializedName注解映射
修改后的Book类示例:
public class Book { private String id, selfLink, title, publisher, publishedDate, description, language, listPriceCurrencyCode, retailPriceCurrencyCode; public JSONArray authors, industryIdentifiers, categories; private Integer pageCount; // 改用包装类 private Double listPriceAmount, retailPriceAmount; // 改用包装类 // 添加无参构造 public Book() {} // 保留原有全参构造 Book(...) { // 原有代码逻辑 } // 生成所有字段的getter和setter方法 }
解析JSON数组的代码会极度简化:
Gson gson = new Gson(); Type bookListType = new TypeToken<ArrayList<Book>>(){}.getType(); ArrayList<Book> bookList = gson.fromJson(jsonString, bookListType);
Gson会自动处理所有缺失字段,不存在的字段会被设为null(包装类),无需任何手动判断。
2. 使用Jackson实现解析
Jackson同样支持异构JSON解析,步骤类似:
引入Jackson依赖,修改Book类添加无参构造,然后配置解析规则:
ObjectMapper objectMapper = new ObjectMapper(); // 配置忽略未知字段,避免JSON中存在类未定义字段时抛出异常 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); List<Book> bookList = objectMapper.readValue(jsonString, new TypeReference<List<Book>>() {});
二、将JSON数组转换为Map列表
完全可以将JSON数组转换为List<Map<String, Object>>,原生JSON库或序列化框架都能实现:
1. 用原生org.json库实现
JSONArray jsonArray = new JSONArray(jsonString); List<Map<String, Object>> mapList = new ArrayList<>(); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); Map<String, Object> map = new HashMap<>(); Iterator<String> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); Object value = jsonObject.get(key); // 递归处理嵌套JSONObject if (value instanceof JSONObject) { value = jsonObjectToMap((JSONObject) value); } // 递归处理嵌套JSONArray else if (value instanceof JSONArray) { value = jsonArrayToList((JSONArray) value); } map.put(key, value); } mapList.add(map); } // 辅助方法:JSONObject转Map private static Map<String, Object> jsonObjectToMap(JSONObject jsonObject) throws JSONException { Map<String, Object> map = new HashMap<>(); Iterator<String> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); Object value = jsonObject.get(key); if (value instanceof JSONObject) { value = jsonObjectToMap((JSONObject) value); } else if (value instanceof JSONArray) { value = jsonArrayToList((JSONArray) value); } map.put(key, value); } return map; } // 辅助方法:JSONArray转List private static List<Object> jsonArrayToList(JSONArray jsonArray) throws JSONException { List<Object> list = new ArrayList<>(); for (int i = 0; i < jsonArray.length(); i++) { Object value = jsonArray.get(i); if (value instanceof JSONObject) { value = jsonObjectToMap((JSONObject) value); } else if (value instanceof JSONArray) { value = jsonArrayToList((JSONArray) value); } list.add(value); } return list; }
2. 用Gson快速转换为Map列表
Gson gson = new Gson(); Type mapListType = new TypeToken<ArrayList<Map<String, Object>>>(){}.getType(); List<Map<String, Object>> mapList = gson.fromJson(jsonString, mapListType);
Gson会自动将嵌套JSON对象转为Map,JSON数组转为List,代码简洁高效。
总结
- 异构JSON解析首选Gson/Jackson这类成熟序列化框架,能大幅减少冗余代码,降低出错概率
- 转换为Map列表完全可行,框架方式实现更简洁,原生库则适合需要自定义转换逻辑的场景
内容的提问来源于stack exchange,提问作者BrainlessPOMO
相关产品推荐
相关产品推荐

