天天看點

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?

昨天下午 5 點 10 分左右,我解決掉了最後一個 bug,輕舒一口氣,準備關機下班。可這個時候,老闆朝我走來,臉上挂着神秘的微笑,我就知道他不懷好意。果不其然,他扔給了我一個新的需求,要我在 Java 中解析 JSON,并且要在半個小時候給出最佳的解決方案。

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?
無奈,提前下班的希望破滅了。不過,按時下班的希望還是有的。于是我撸起袖子開始了研究,結果出乎我的意料,竟然不到 10 分鐘就找出了最佳方案。但我假裝還沒有搞出來,趁着下班前的這段時間把方案整理成了現在你們看到的這篇文章。

01、JSON 是什麼

JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,易于閱讀和編寫,機器解析和生成起來更是輕而易舉。JSON 采用了完全獨立于程式設計語言的文本格式,但它的格式非常符合 C 語言家族的習慣(比如 C、C++、C#、Java、JavaScript、Python 等)。 這種特質使得 JSON 成為了最理想的資料交換格式。

JSON 建構于兩種常見的資料結構:

  • “鍵/值”對。
  • 數組。

這使得 JSON 在同樣基于這些結構的程式設計語言之間的交換成為可能。在 Java 中,解析 JSON 的第三方類庫有很多,比如說下面這些。

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?

很多,對不對?但日常開發中,最常用的隻有四個:Gson、Jackson、org.json 和阿裡巴巴的 fastjson。下面我們來簡單地對比下。

02、Gson

Gson 是谷歌提供的一個開源庫,可以将 Java 對象序列化為 JSON 字元串,同樣可以将 JSON 字元串反序列化(解析)為比對的 Java 對象。

使用 Gson 之前,需要先在項目中引入 Gson 的依賴。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
    <scope>compile</scope>
</dependency>
           

1)簡單示例

Gson gson = new Gson();
gson.toJson(18);            // ==> 18
gson.toJson("沉默王二");       // ==> "沉默王二"
           

上面這段代碼通過

new

關鍵字建立了一個 Gson 對象,然後調用其

toJson()

方法将整形和字元串轉成了 JSON 字元串。

同樣,可以調用

fromJson()

方法将簡單的 JSON 字元串解析為整形和字元串。

int one = gson.fromJson("18", int.class);
Integer one1 = gson.fromJson("18", Integer.class);
String str = gson.fromJson("\"沉默王二\"", String.class);
           

2)複雜點的示例

Cmower 類有兩個字段:整形 age 和 字元串 name。

class Cmower {
    private int age = 18;
    private String name = "沉默王二";
}
           

将其轉成 JSON 字元串。

Gson gson = new Gson();
String json = gson.toJson(new Cmower());
System.out.println(json);
           

輸出結果為:

{"age":18,"name":"沉默王二"}
           

可以再通過

fromJson()

方法将字元串 json 解析為 Java 對象。

gson.fromJson(json, Cmower.class);
           

3)數組示例

Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"沉", "默", "王二"};

// 轉成 JSON 字元串
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  // ==> ["沉", "默", "王二"]

// 解析為數組
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
String[] strings2 = gson.fromJson("[\"沉\", \"默\", \"王二\"]", String[].class);
           

數組的處理仍然非常簡單,調用的方法也仍然是

toJson()

fromJson()

方法。

4)集合示例

Gson gson = new Gson();
List<String> list = new ArrayList<>(Arrays.asList("沉", "默", "王二"));
String json = gson.toJson(list); // ==> ["沉","默","王二"]
           

把集合轉成 JSON 字元串并沒有什麼特别之處,不過,把 JSON 字元串解析為集合就和之前的方法有些不同了。

Type collectionType = new TypeToken<ArrayList<String>>(){}.getType();
List<String> list2 = gson.fromJson(json, collectionType);
           

我們需要借助

com.google.gson.reflect.TypeToken

java.lang.reflect.Type

來擷取集合的類型,再将其作為參數傳遞給

formJson()

方法,才能将 JSON 字元串解析為集合。

Gson 雖然可以将任意的 Java 對象轉成 JSON 字元串,但将字元串解析為指定的集合類型時就需要花點心思了,因為涉及到了泛型——TypeToken 是解決這個問題的銀彈。

關于 Gson,我們就先說到這吧,以後有機會的時候再和大家細說。

03、Jackson

Jackson 是基于 Stream 建構的一款用來序列化和反序列化 JSON 的 Java 開源庫,社群非常活躍,其版本的更新速度也比較快。

  • 截止到目前,GitHub 上已經星标 5.2K 了;
  • Spring MVC 的預設 JSON 解析器;
  • 與 Gson 相比,Jackson 在解析大的 JSON 檔案時速度更快。
  • 與 fastjson 相比,Jackson 更穩定。

在使用 Jackson 之前,需要先添加 Jackson 的依賴。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.1</version>
</dependency>
           

Jackson 的核心子產品由三部分組成。

  • jackson-core,核心包,提供基于"流模式"解析的相關 API,它包括 JsonPaser 和 JsonGenerator。
  • jackson-annotations,注解包,提供标準注解功能。
  • jackson-databind ,資料綁定包, 提供基于"對象綁定" 解析的相關 API ( ObjectMapper ) 和"樹模型" 解析的相關 API (JsonNode);基于"對象綁定" 解析的 API 和"樹模型"解析的 API 依賴基于"流模式"解析的 API。

當添加 jackson-databind 之後, jackson-core 和 jackson-annotations 也随之添加到 Java 項目工程中。

這裡順帶推薦一個 IDEA 插件:JsonFormat,可以将 JSON 字元串生成一個 JavaBean。怎麼使用呢?可以建立一個類,然後調出 Generate 菜單。

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?

選擇 JsonFormat,輸入 JSON 字元串。

{
  "age" : 18,
  "name" : "沉默王二"
}
           

确認後生成 JavaBean,生成的内容如下所示。

public class Cmower {
    private Integer age;
    private String name;

    public Cmower() {
    }

    public Cmower(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
           

那怎麼使用 Jackson 呢?上文已經提到,ObjectMapper 是 Jackson 最常用的 API,我們來看一個簡單的示例。

Cmower wanger = new Cmower(18,"沉默王二");
System.out.println(wanger);

ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(wanger);

System.out.println(jsonString);

Cmower deserialize = mapper.readValue(jsonString,Cmower.class);
System.out.println(deserialize);
           

ObjectMapper 通過

writeValue()

的系列方法可以将 Java 對象序列化為 JSON,并将 JSON 存儲成不同的格式。

  • String(writeValueAsString)
  • Byte Array(writeValueAsBytes)

readValue()

系列方法可以從不同的資料源(String、Bytes)将 JSON 反序列化(解析)為 Java 對象。

程式輸出結果為:

com.cmower.java_demo.jackson.Cmower@214c265e
{
  "age" : 18,
  "name" : "沉默王二"
}
com.cmower.java_demo.jackson.Cmower@612fc6eb
           

在調用

writeValue()

或者

readValue()

方法之前,往往需要對 JSON 和 JavaBean 之間進行一些定制化配置。

1)在反序列化時忽略在 JSON 中存在但 JavaBean 不存在的字段

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
           

2)在序列化時忽略值為 null 的字段

apper.setSerializationInclusion(Include.NON_NULL); 
           

有些時候,這些定制化的配置對 JSON 和 JavaBean 之間的轉化起着重要的作用。如果需要更多配置資訊,檢視 DeserializationFeature、SerializationFeature 和 Include 類的 Javadoc 即可。

關于 Jackson,我們就說到這吧,以後有機會的時候再和大家細說。

04、org.json

org.json 是 JSON 官方提供的一個開源庫,不過使用起來就略顯繁瑣了。

使用 org.json 之前,需要先在項目中引入 org.json 的依賴。

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20190722</version>
</dependency>
           

org.json.JSONObject

類可以通過 new 關鍵字将 JSON 字元串解析為 Java 對象,然後 get 的系列方法擷取對應的鍵值,代碼示例如下所示。

String str = "{ \"name\": \"沉默王二\", \"age\": 18 }";
JSONObject obj = new JSONObject(str);
String name = obj.getString("name");
int age = obj.getInt("age");
           

調用

org.json.JSONObject

類的

getJSONArray()

方法可以傳回一個表示數組的

org.json.JSONArray

對象,再通過循環的方式可以擷取數組中的元素,代碼示例如下所示。

String str = "{ \"number\": [3, 4, 5, 6] }";
JSONObject obj = new JSONObject(str);
JSONArray arr = obj.getJSONArray("number");
for (int i = 0; i < arr.length(); i++) {
    System.out.println(arr.getInt(i));
}
           

如果想擷取 JSON 字元串,可以使用

put()

方法将鍵值對放入

org.json.JSONObject

對象中,再調用

toString()

方法即可,代碼示例如下所示。

JSONObject obj = new JSONObject();
obj.put("name","沉默王二");
obj.put("age",18);
System.out.println(obj.toString()); // {"name":"沉默王二","age":18}
           

相比較于 Gson 和 Jackson 來說,org.json 就要遜色多了,不僅不夠靈活,API 也不夠豐富。

05、fastjson

fastjson 是阿裡巴巴開源的 JSON 解析庫,它可以解析 JSON 格式的字元串,也支援将 Java Bean 序列化為 JSON 字元串。

fastjson 相對于其他 JSON 庫的特點就是快,另外 API 使用起來也非常簡單,更是在 2012 年被開源中國評選為最受歡迎的國産開源軟體之一。

PS:盡管 fastjson 值得信賴,但也鬧過不少腥風血雨,這裡就不提了。

在使用 fastjson 之前,需要先添加 fastjson 的依賴。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.61</version>
</dependency>
           

那怎麼使用 fastjson 呢?我們來建立一個 Java Bean,有三個字段:年齡 age,名字 name,清單 books。

class Cmower1 {
    private Integer age;
    private String name;
    private List<String> books = new ArrayList<>();

    public Cmower1(Integer age, String name) {
        this.age = age;
        this.name = name;
    }
   // getter/setter

    public void putBook(String bookname) {
        this.books.add(bookname);
    }
}
           

然後我們使用

JSON.toJSONString()

将 Java 對象序列化為 JSON 字元串,代碼示例如下:

Cmower1 cmower = new Cmower1(18,"沉默王二");
cmower.putBook("《Web全棧開發進階之路》");
String jsonString = JSON.toJSONString(cmower);
System.out.println(jsonString);
           

程式輸出:

{"age":18,"books":["《Web全棧開發進階之路》"],"name":"沉默王二"}
           

那如何解析 JSON 字元串呢?使用

JSON.parseObject()

方法,代碼示例如下所示。

JSON.parseObject(jsonString, Cmower1.class)
           

06、總結

就我個人而言,我是比較推崇 Gson 的,畢竟是谷歌出品的,品質值得信賴,關鍵是用起來也确實比較得勁。

Jackson 呢,在解析大的 JSON 檔案時速度更快,也比 fastjson 穩定。

fastjson 呢,作為我們國産開源軟體中的驕傲,嗯,值得尊敬。

令我意外的是,org.json 在 StackOverflow 上一個 160 萬浏覽量的提問中,牢牢地占據頭名答案。更令我想不到的是,老闆竟然也選擇了 org.json,說它比較原生,JSON 官方的親兒子。

我。。。。。。

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?

07、鳴謝

好了,各位讀者朋友們,以上就是本文的全部内容了。能看到這裡的都是最優秀的程式員,升職加薪就是你了👍。如果覺得不過瘾,還想看到更多,我再推薦一篇給大家。

還有一周就解放了,無心撸碼,着急回家

原創不易,如果覺得有點用的話,請不要吝啬你手中點贊的權力;如果想要第一時間看到二哥更新的文章,請掃描下方的二維碼,關注沉默王二公衆号。我們下篇文章見!

除了鬧過腥風血雨的fastjson,你還知道哪些Java解析JSON的利器?

微信掃描左側二維碼,關注作者的微信公衆号:「

沉默王二

背景回複“

666

”即可擷取一份 500G 的高清教學視訊,并且已經分門别類,可以按需下載下傳,速去!

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

如果覺得還有幫助的話,可以點一下右下角的【推薦】。