You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

疑问:

  1. 这种大量if判断的解析方式不够优雅,有没有更好的方法解析此类含大量异构条目的JSON文件?
  2. 能否将整个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:35:31