Java四大常用JSON解析工具性能對(duì)比(Hutool、Fastjson2、Gson與Jackson)
1. 引言
JSON 是現(xiàn)代軟件開發(fā)中常用的數(shù)據(jù)交換格式,尤其在微服務(wù)和前后端分離的架構(gòu)中更是必不可少。
本文將對(duì) Java 中四大主流 JSON 解析庫——Hutool、Fastjson2、Gson 和 Jackson 進(jìn)行性能測試和對(duì)比分析,通過實(shí)測 20 萬條數(shù)據(jù)解析,揭示各庫在批量和逐條處理中的表現(xiàn)。
測試結(jié)果僅供參考?。?! 請(qǐng)多次測試再抉擇
2. 環(huán)境與依賴
2.1 環(huán)境信息
操作系統(tǒng):Window11
JDK 版本:jdk1.8.0_281
CPU : AMD Ryzen 9 7945HX
內(nèi)存:32GB
2.2 Maven依賴
在項(xiàng)目的 pom.xml 文件中引入以下依賴:
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.52</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.35</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
3. 測試代碼
3.1 數(shù)據(jù)模型
定義一個(gè)簡單的實(shí)體對(duì)象:
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author 阿水 */ @Data @AllArgsConstructor @NoArgsConstructor public class Variable { private int id; private String name; private double value; private String description; private String type; }
3.2 測試數(shù)據(jù)生成
模擬 20 萬條數(shù)據(jù)用于測試:
// 生成測試數(shù)據(jù) public static List<Variable> generateData(int size) { List<Variable> list = new ArrayList<>(size); for (int i = 0; i < size; i++) { Variable data = new Variable(); data.setId(i); data.setName("Name" + i); data.setValue(Math.random() * 1000); data.setDescription(IdUtil.fastSimpleUUID()); data.setType(IdUtil.fastSimpleUUID()+i); list.add(data); } return list; }
3.3 四大庫序列化與反序列化測試
import cn.hutool.core.util.IdUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSON; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * @description: JSON 序列化、解析性能測試 * @author 阿水 */ @Slf4j public class JsonBenchmarkTest { //數(shù)據(jù)總條數(shù) public static int dataSize = 200000; //測試次數(shù) public static int iterations = 10; public static void main(String[] args) throws Exception { // 生成測試數(shù)據(jù) List<Variable> testData = generateData(dataSize); log.info("測試數(shù)據(jù)總條數(shù)為: {} 條", dataSize); log.info("以下測試結(jié)果均為進(jìn)行 {} 次計(jì)算之后,耗費(fèi)時(shí)間取平均值計(jì)算得出。", iterations); // 序列化測試 String jsonString = serializationTest(testData); log.info("JSON 數(shù)據(jù)總大小為: {} 字節(jié)", jsonString.length()); // 批量解析測試 log.info("===== 使用批量解析 JSON(即解析集合API)====="); batchParseTest(jsonString); // 單條解析測試 log.info("===== 循環(huán)遍歷逐個(gè)解析 JSON API ====="); singleParseTest(jsonString); // 單條解析并插入集合測試 log.info("===== 循環(huán)遍歷逐個(gè)解析 JSON并插入集合 API====="); singleParseAndAddListTest(jsonString); } // 生成測試數(shù)據(jù) public static List<Variable> generateData(int size) { List<Variable> list = new ArrayList<>(size); for (int i = 0; i < size; i++) { Variable data = new Variable(); data.setId(i); data.setName("Name" + i); data.setValue(Math.random() * 1000); data.setDescription(IdUtil.fastSimpleUUID()); data.setType(IdUtil.fastSimpleUUID()+i); list.add(data); } return list; } /** * 序列化測試 */ private static String serializationTest(List<Variable> testData) throws Exception { String jsonResult = null; // Hutool long hutoolTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); String hutoolJson = JSONUtil.toJsonStr(testData); long end = System.currentTimeMillis(); hutoolTotal += (end - start); if (i == 0) jsonResult = hutoolJson; // 保存結(jié)果 } log.info("HuTool 序列化平均耗時(shí): {} ms", hutoolTotal / iterations); // Fastjson2 long fastjsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); String fastjsonJson = JSON.toJSONString(testData); long end = System.currentTimeMillis(); fastjsonTotal += (end - start); } log.info("Fastjson2 序列化平均耗時(shí): {} ms", fastjsonTotal / iterations); // Gson Gson gson = new Gson(); long gsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); String gsonJson = gson.toJson(testData); long end = System.currentTimeMillis(); gsonTotal += (end - start); } log.info("Gson 序列化平均耗時(shí): {} ms", gsonTotal / iterations); // Jackson ObjectMapper objectMapper = new ObjectMapper(); long jacksonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); String jacksonJson = objectMapper.writeValueAsString(testData); long end = System.currentTimeMillis(); jacksonTotal += (end - start); } log.info("Jackson 序列化平均耗時(shí): {} ms", jacksonTotal / iterations); return jsonResult; } /** * 批量解析測試 */ private static void batchParseTest(String jsonString) throws Exception { // Hutool long hutoolTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); List<Variable> result = JSONUtil.toList(JSONUtil.parseArray(jsonString), Variable.class); long end = System.currentTimeMillis(); hutoolTotal += (end - start); } log.info("HuTool 批量解析平均耗時(shí): {} ms", hutoolTotal / iterations); // Fastjson2 long fastjsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); List<Variable> result = JSON.parseArray(jsonString, Variable.class); long end = System.currentTimeMillis(); fastjsonTotal += (end - start); } log.info("Fastjson2 批量解析平均耗時(shí): {} ms", fastjsonTotal / iterations); // Gson Gson gson = new Gson(); long gsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); List<Variable> result = gson.fromJson(jsonString, new TypeToken<List<Variable>>() {}.getType()); long end = System.currentTimeMillis(); gsonTotal += (end - start); } log.info("Gson 批量解析平均耗時(shí): {} ms", gsonTotal / iterations); // Jackson ObjectMapper objectMapper = new ObjectMapper(); long jacksonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); List<Variable> result = objectMapper.readValue(jsonString, new TypeReference<List<Variable>>() {}); long end = System.currentTimeMillis(); jacksonTotal += (end - start); } log.info("Jackson 批量解析平均耗時(shí): {} ms", jacksonTotal / iterations); } /** * 單條解析測試 */ private static void singleParseTest(String jsonString) throws Exception { List<String> messageList = JSON.parseArray(jsonString, Variable.class).stream() .map(JSON::toJSONString) .collect(Collectors.toList()); // Hutool long hutoolTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); for (String msg : messageList) { Variable v = JSONUtil.toBean(msg, Variable.class); } long end = System.currentTimeMillis(); hutoolTotal += (end - start); } log.info("HuTool 單條解析平均耗時(shí): {} ms", hutoolTotal / iterations); // Fastjson2 long fastjsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); for (String msg : messageList) { Variable v = JSON.parseObject(msg, Variable.class); } long end = System.currentTimeMillis(); fastjsonTotal += (end - start); } log.info("Fastjson2 單條解析平均耗時(shí): {} ms", fastjsonTotal / iterations); // Gson Gson gson = new Gson(); long gsonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); for (String msg : messageList) { Variable v = gson.fromJson(msg, Variable.class); } long end = System.currentTimeMillis(); gsonTotal += (end - start); } log.info("Gson 單條解析平均耗時(shí): {} ms", gsonTotal / iterations); // Jackson ObjectMapper objectMapper = new ObjectMapper(); long jacksonTotal = 0; for (int i = 0; i < iterations; i++) { long start = System.currentTimeMillis(); for (String msg : messageList) { Variable v = objectMapper.readValue(msg, Variable.class); } long end = System.currentTimeMillis(); jacksonTotal += (end - start); } log.info("Jackson 單條解析平均耗時(shí): {} ms", jacksonTotal / iterations); } /** * 循環(huán)遍歷單條解析并插入集合測試 */ /** * 循環(huán)遍歷單條解析并插入集合測試 (平均耗時(shí)計(jì)算) */ static void singleParseAndAddListTest(String jsonString) throws Exception { // 轉(zhuǎn)換為模擬 MQ 消息體 List<String> messageList = JSON.parseArray(jsonString, Variable.class).stream() .map(JSON::toJSONString) // 將每個(gè)對(duì)象轉(zhuǎn)為 JSON 字符串模擬單條消息 .collect(Collectors.toList()); // 平均耗時(shí)變量定義 double hutoolTotalTime = 0; double fastjsonTotalTime = 0; double gsonTotalTime = 0; double jacksonTotalTime = 0; // 循環(huán) 10 次計(jì)算平均耗時(shí) for (int i = 0; i < iterations; i++) { // 1. Hutool JSONUtil 單條解析 List<Variable> hutoolList = new ArrayList<>(); long hutoolStart = System.currentTimeMillis(); for (String msg : messageList) { Variable v = JSONUtil.toBean(msg, Variable.class); hutoolList.add(v); // 將對(duì)象存入集合 } long hutoolEnd = System.currentTimeMillis(); hutoolTotalTime += (hutoolEnd - hutoolStart); // 2. Fastjson2 單條解析 List<Variable> fastjsonList = new ArrayList<>(); long fastjsonStart = System.currentTimeMillis(); for (String msg : messageList) { Variable v = JSON.parseObject(msg, Variable.class); fastjsonList.add(v); } long fastjsonEnd = System.currentTimeMillis(); fastjsonTotalTime += (fastjsonEnd - fastjsonStart); // 3. Gson 單條解析 List<Variable> gsonList = new ArrayList<>(); Gson gson = new Gson(); long gsonStart = System.currentTimeMillis(); for (String msg : messageList) { Variable v = gson.fromJson(msg, Variable.class); gsonList.add(v); } long gsonEnd = System.currentTimeMillis(); gsonTotalTime += (gsonEnd - gsonStart); // 4. Jackson 單條解析 List<Variable> jacksonList = new ArrayList<>(); ObjectMapper objectMapper = new ObjectMapper(); long jacksonStart = System.currentTimeMillis(); for (String msg : messageList) { Variable v = objectMapper.readValue(msg, Variable.class); jacksonList.add(v); } long jacksonEnd = System.currentTimeMillis(); jacksonTotalTime += (jacksonEnd - jacksonStart); } // 輸出平均耗時(shí)結(jié)果 log.info("HuTool 單條解析并存入集合平均耗時(shí): {} ms", hutoolTotalTime / iterations); log.info("Fastjson2 單條解析并存入集合平均耗時(shí): {} ms", fastjsonTotalTime / iterations); log.info("Gson 單條解析并存入集合平均耗時(shí): {} ms", gsonTotalTime / iterations); log.info("Jackson 單條解析并存入集合平均耗時(shí): {} ms", jacksonTotalTime / iterations); } }
4.結(jié)果分析
20W條數(shù)據(jù)、31098673字節(jié)測試結(jié)果分析(僅供參考 僅供參考 僅供參考 !?。。?/strong>
庫名稱 | 序列化+反序列化總耗時(shí) | 性能排名 |
---|---|---|
Fastjson2 | 110ms左右 | 第一名 |
Jackson | 170ms左右 | 第二名 |
Gson | 210ms左右 | 第三名 |
Hutool | 1800ms左右 | 第四名 |
5. 性能分析與總結(jié)
測試結(jié)果分析
1.Fastjson2
- 性能表現(xiàn): 測試結(jié)果中,無論是批量解析、逐條解析還是逐條解析并插入集合,它的速度都是最快的(30ms、39ms、39.8ms)。
- 特性優(yōu)勢: 支持復(fù)雜對(duì)象結(jié)構(gòu)解析,API 設(shè)計(jì)簡潔高效,并修復(fù)了舊版 Fastjson 的反序列化漏洞,安全性更高。
- 適用場景: 高并發(fā)、大數(shù)據(jù)量處理及性能敏感型應(yīng)用場景。
2.Hutool
- 性能表現(xiàn): 表現(xiàn)最慢,尤其在批量解析(637ms)和逐條解析(589ms)中遠(yuǎn)落后于其他庫。
- 特性優(yōu)勢: API 優(yōu)雅輕便,開發(fā)效率高,但性能瓶頸明顯,不適合超大規(guī)模數(shù)據(jù)解析。
- 適用場景: 適合中小規(guī)模項(xiàng)目的快速開發(fā),便捷性優(yōu)先于性能要求的場合。
3.Jackson
- 性能表現(xiàn): 表現(xiàn)較優(yōu),解析速度僅次于 Fastjson2(78ms、101ms、99.8ms),兼顧性能與功能復(fù)雜性。
- 特性優(yōu)勢: 支持復(fù)雜 Java 對(duì)象和自定義配置,兼容性強(qiáng),適合復(fù)雜數(shù)據(jù)結(jié)構(gòu)映射需求。
- 適用場景: 企業(yè)級(jí)應(yīng)用、大型復(fù)雜系統(tǒng)開發(fā)及對(duì)靈活性要求高的項(xiàng)目。
4.Gson
- 性能表現(xiàn): 性能優(yōu)于 Hutool,但低于 Fastjson2 和 Jackson(93ms、119ms、119.5ms)。
- 特性優(yōu)勢: API 簡單直觀,開發(fā)成本低,但在大數(shù)據(jù)量或高并發(fā)處理時(shí)性能表現(xiàn)不夠理想。
- 適用場景: 小規(guī)模數(shù)據(jù)解析需求,或?qū)π阅芤蟛桓叩娜蝿?wù)。
6. 推薦選擇
求類型 | 推薦庫 | 適用場景描述 |
---|---|---|
性能優(yōu)先 | Fastjson2 | 在所有測試場景中速度最快,適合高性能和高并發(fā)場景,適合日志分析、大數(shù)據(jù)處理和消息隊(duì)列數(shù)據(jù)解析等應(yīng)用 |
輕量便捷 | Hutool | 更適合中小規(guī)模項(xiàng)目的快速開發(fā),雖然性能較低,但 API 優(yōu)雅輕便,適合便捷性優(yōu)先的場合 |
功能復(fù)雜需求 | Jackson | 兼顧性能與靈活性,支持復(fù)雜數(shù)據(jù)結(jié)構(gòu)和自定義配置,適合大型企業(yè)級(jí)應(yīng)用或復(fù)雜對(duì)象映射需求 |
簡單解析需求 | Gson | API 簡潔易用,適合小規(guī)模數(shù)據(jù)解析任務(wù),學(xué)習(xí)成本低,但不適合大數(shù)據(jù)和高并發(fā)需求 |
7. 結(jié)論與建議
Fastjson2:
- 性能最高,適合高并發(fā)與大數(shù)據(jù)處理需求。
- 安全性較高,是性能敏感應(yīng)用的首選。
Hutool:
- 開發(fā)便捷但性能較低,適合中小規(guī)模項(xiàng)目。
- 如果對(duì)開發(fā)效率要求高且數(shù)據(jù)量適中,可以選擇它。
Jackson:
- 性能與靈活性兼顧,適合復(fù)雜對(duì)象和企業(yè)級(jí)系統(tǒng)。
- 面向需要自定義解析規(guī)則的場景表現(xiàn)更出色。
Gson:
- 簡單易用但性能低于 Fastjson2 和 Jackson。
- 適合小型項(xiàng)目或?qū)π阅芤蟛桓叩膱龊稀?/li>
注意事項(xiàng)
- 安全性: Fastjson2 安全性最佳,其他庫需關(guān)注版本更新,以避免反序列化漏洞。
- 兼容性: Jackson 在跨平臺(tái)兼容性和復(fù)雜結(jié)構(gòu)處理方面表現(xiàn)更佳。
- 性能評(píng)估: 項(xiàng)目正式使用前,應(yīng)基于實(shí)際生產(chǎn)環(huán)境進(jìn)行更大規(guī)模的性能測試和壓力測試。
僅當(dāng)前測試數(shù)據(jù)明確顯示:
- Fastjson2 性能最佳,適合高性能需求。
- Hutool 性能最慢,更適合便捷開發(fā)而非大規(guī)模數(shù)據(jù)解析。
- Jackson 在性能和靈活性之間取得平衡,適合復(fù)雜應(yīng)用場景。
- Gson 表現(xiàn)優(yōu)于 Hutool,但略遜于 Fastjson2 和 Jackson,適合輕量級(jí)需求。
到此這篇關(guān)于Java四大常用JSON解析工具性能對(duì)比(Hutool、Fastjson2、Gson與Jackson)的文章就介紹到這了,更多相關(guān)Java解析JSON內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)JDK動(dòng)態(tài)代理的原理詳解
這篇文章主要介紹了Java實(shí)現(xiàn)JDK動(dòng)態(tài)代理的原理詳解,Java常用的動(dòng)態(tài)代理模式有JDK動(dòng)態(tài)代理,也有cglib動(dòng)態(tài)代理,本文重點(diǎn)講解JDK的動(dòng)態(tài)代理,需要的小伙伴可以參考一下的相關(guān)資料2022-07-07Spring?Boot如何配置yml配置文件定義集合、數(shù)組和Map
這篇文章主要介紹了Spring?Boot?優(yōu)雅配置yml配置文件定義集合、數(shù)組和Map,包括Spring?Boot?yml配置文件定義基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的方式,需要的朋友可以參考下2023-10-10SpringBoot整合EasyCaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot整合EasyCaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-02-02