1. 引言
JSON 是现代软件开发中常用的数据交换格式,尤其在微服务和前后端分离的架构中更是必不可少。
本文将对 Java 中四大主流 JSON 解析库——Hutool、Fastjson2、Gson 和 Jackson 进行性能测试和对比分析,通过实测 20 万条数据解析,揭示各库在批量和逐条处理中的表现。
测试结果仅供参考!!! 请多次测试再抉择
2. 环境与依赖
2.1 环境信息
- 操作系统:Window11
- JDK 版本:jdk1.8.0_281
- CPU : AMD Ryzen 9 7945HX
- 内存:32GB
2.2 Maven依赖
在项目的 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 数据模型
定义一个简单的实体对象:
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 测试数据生成
模拟 20 万条数据用于测试:
// 生成测试数据 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 { //数据总条数 public static int dataSize = 200000; //测试次数 public static int iterations = 10; public static void main(String[] args) throws Exception { // 生成测试数据 List<Variable> testData = generateData(dataSize); log.info("测试数据总条数为: {} 条", dataSize); log.info("以下测试结果均为进行 {} 次计算之后,耗费时间取平均值计算得出。", iterations); // 序列化测试 String jsonString = serializationTest(testData); log.info("JSON 数据总大小为: {} 字节", jsonString.length()); // 批量解析测试 log.info("===== 使用批量解析 JSON(即解析集合API)====="); batchParseTest(jsonString); // 单条解析测试 log.info("===== 循环遍历逐个解析 JSON API ====="); singleParseTest(jsonString); // 单条解析并插入集合测试 log.info("===== 循环遍历逐个解析 JSON并插入集合 API====="); singleParseAndAddListTest(jsonString); } // 生成测试数据 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; // 保存结果 } log.info("HuTool 序列化平均耗时: {} 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 序列化平均耗时: {} 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 序列化平均耗时: {} 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 序列化平均耗时: {} 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 批量解析平均耗时: {} 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 批量解析平均耗时: {} 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 批量解析平均耗时: {} 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 批量解析平均耗时: {} 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 单条解析平均耗时: {} 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 单条解析平均耗时: {} 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 单条解析平均耗时: {} 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 单条解析平均耗时: {} ms", jacksonTotal / iterations); } /** * 循环遍历单条解析并插入集合测试 */ /** * 循环遍历单条解析并插入集合测试 (平均耗时计算) */ static void singleParseAndAddListTest(String jsonString) throws Exception { // 转换为模拟 MQ 消息体 List<String> messageList = JSON.parseArray(jsonString, Variable.class).stream() .map(JSON::toJSONString) // 将每个对象转为 JSON 字符串模拟单条消息 .collect(Collectors.toList()); // 平均耗时变量定义 double hutoolTotalTime = 0; double fastjsonTotalTime = 0; double gsonTotalTime = 0; double jacksonTotalTime = 0; // 循环 10 次计算平均耗时 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); // 将对象存入集合 } 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); } // 输出平均耗时结果 log.info("HuTool 单条解析并存入集合平均耗时: {} ms", hutoolTotalTime / iterations); log.info("Fastjson2 单条解析并存入集合平均耗时: {} ms", fastjsonTotalTime / iterations); log.info("Gson 单条解析并存入集合平均耗时: {} ms", gsonTotalTime / iterations); log.info("Jackson 单条解析并存入集合平均耗时: {} ms", jacksonTotalTime / iterations); } }
复制
4. 20W条数据、31098673字节测试结果分析(仅供参考 仅供参考 仅供参考 !!!)
库名称 | 序列化+反序列化总耗时 | 性能排名 |
---|---|---|
Fastjson2 | 110ms左右 | 🥇 第一名 |
Jackson | 170ms左右 | 🥈 第二名 |
Gson | 210ms左右 | 🥉 第三名 |
Hutool | 1800ms左右 | 第四名 |
5. 性能分析与总结
测试结果分析
-
Fastjson2
- 性能表现: 测试结果中,无论是批量解析、逐条解析还是逐条解析并插入集合,它的速度都是最快的(30ms、39ms、39.8ms)。
- 特性优势: 支持复杂对象结构解析,API 设计简洁高效,并修复了旧版 Fastjson 的反序列化漏洞,安全性更高。
- 适用场景: 高并发、大数据量处理及性能敏感型应用场景。
-
Hutool
- 性能表现: 表现最慢,尤其在批量解析(637ms)和逐条解析(589ms)中远落后于其他库。
- 特性优势: API 优雅轻便,开发效率高,但性能瓶颈明显,不适合超大规模数据解析。
- 适用场景: 适合中小规模项目的快速开发,便捷性优先于性能要求的场合。
-
Jackson
- 性能表现: 表现较优,解析速度仅次于 Fastjson2(78ms、101ms、99.8ms),兼顾性能与功能复杂性。
- 特性优势: 支持复杂 Java 对象和自定义配置,兼容性强,适合复杂数据结构映射需求。
- 适用场景: 企业级应用、大型复杂系统开发及对灵活性要求高的项目。
-
Gson
- 性能表现: 性能优于 Hutool,但低于 Fastjson2 和 Jackson(93ms、119ms、119.5ms)。
- 特性优势: API 简单直观,开发成本低,但在大数据量或高并发处理时性能表现不够理想。
- 适用场景: 小规模数据解析需求,或对性能要求不高的任务。
6. 推荐选择
需求类型 | 推荐库 | 适用场景描述 |
---|---|---|
性能优先 | Fastjson2 | 在所有测试场景中速度最快,适合高性能和高并发场景,适合日志分析、大数据处理和消息队列数据解析等应用。 |
轻量便捷 | Hutool | 更适合中小规模项目的快速开发,虽然性能较低,但 API 优雅轻便,适合便捷性优先的场合。 |
功能复杂需求 | Jackson | 兼顾性能与灵活性,支持复杂数据结构和自定义配置,适合大型企业级应用或复杂对象映射需求。 |
简单解析需求 | Gson | API 简洁易用,适合小规模数据解析任务,学习成本低,但不适合大数据和高并发需求。 |
7. 结论与建议
-
Fastjson2:
- 性能最高,适合高并发与大数据处理需求。
- 安全性较高,是性能敏感应用的首选。
-
Hutool:
- 开发便捷但性能较低,适合中小规模项目。
- 如果对开发效率要求高且数据量适中,可以选择它。
-
Jackson:
- 性能与灵活性兼顾,适合复杂对象和企业级系统。
- 面向需要自定义解析规则的场景表现更出色。
-
Gson:
- 简单易用但性能低于 Fastjson2 和 Jackson。
- 适合小型项目或对性能要求不高的场合。
注意事项
- 安全性: Fastjson2 安全性最佳,其他库需关注版本更新,以避免反序列化漏洞。
- 兼容性: Jackson 在跨平台兼容性和复杂结构处理方面表现更佳。
- 性能评估: 项目正式使用前,应基于实际生产环境进行更大规模的性能测试和压力测试。
仅当前测试数据明确显示:
- Fastjson2 性能最佳,适合高性能需求。
- Hutool 性能最慢,更适合便捷开发而非大规模数据解析。
- Jackson 在性能和灵活性之间取得平衡,适合复杂应用场景。
- Gson 表现优于 Hutool,但略逊于 Fastjson2 和 Jackson,适合轻量级需求。