首页 > 编程语言 >Java中常用的JSON库,哪个性能更牛?

Java中常用的JSON库,哪个性能更牛?

时间:2022-11-14 10:38:53浏览次数:45  
标签:jsonStr count Jackson 更牛 json JSON Java friends


前言

每次都在网上看到别人说什么某某库性能是如何如何的好,碾压其他的库。但是百闻不如一见,只有自己亲手测试过的才是最值得相信的,本篇通过JMH来测试一下Java中几种常见的JSON解析库的性能。

JSON不管是在Web开发还是服务器开发中是相当常见的数据传输格式,一般情况我们对于JSON解析构造的性能并不需要过于关心,除非是在性能要求比较高的系统。

目前对于Java开源的JSON类库有很多种,下面我们取4个常用的JSON库进行性能测试对比, 同时根据测试结果分析如果根据实际应用场景选择最合适的JSON库。

这4个JSON类库分别为:Gson,FastJson,Jackson,Json-lib。

一、简单介绍

选择一个合适的JSON库要从多个方面进行考虑:

  1. 字符串解析成JSON性能
  2. 字符串解析成JavaBean性能
  3. JavaBean构造JSON性能
  4. 集合构造JSON性能
  5. 易用性

先简单介绍下四个类库的身份背景

1.1 Gson

项目地址:https://github.com/google/gson

Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。 Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。 在使用这种对象转换之前,需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。 类里面只要有get和set方法,Gson完全可以实现复杂类型的json到bean或bean到json的转换,是JSON解析的神器。

1.2 FastJson

项目地址:https://github.com/alibaba/fastjson

Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。 FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。 FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。

1.3 Jackson

项目地址:https://github.com/FasterXML/jackson

Jackson是当前用的比较广泛的,用来序列化和反序列化json的Java开源框架。Jackson社区相对比较活跃,更新速度也比较快, 从Github中的统计来看,Jackson是最流行的json解析器之一,Spring MVC的默认json解析器便是Jackson。

Jackson优点很多:

  1. Jackson 所依赖的jar包较少,简单易用。
  2. 与其他 Java 的 json 的框架 Gson 等相比,Jackson 解析大的 json 文件速度比较快。
  3. Jackson 运行时占用内存比较低,性能比较好
  4. Jackson 有灵活的 API,可以很容易进行扩展和定制。

目前最新版本是2.9.4,Jackson 的核心模块由三部分组成:

  1. jackson-core 核心包,提供基于”流模式”解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  2. jackson-annotations 注解包,提供标准注解功能;
  3. jackson-databind 数据绑定包,提供基于”对象绑定” 解析的相关 API( ObjectMapper )和”树模型” 解析的相关 API(JsonNode);基于”对象绑定” 解析的 API 和”树模型”解析的 API 依赖基于”流模式”解析的 API。

为什么Jackson的介绍这么长啊?因为它也是本人的最爱。

1.4 Json-lib

项目地址:http://json-lib.sourceforge.net/index.html

json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷, 比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能满足现在互联网化的需求。

二、编写性能测试

接下来开始编写这四个库的性能测试代码。

2.1 添加maven依赖

当然首先是添加四个库的maven依赖,公平起见,我全部使用它们最新的版本:


1. ​​<!-- Json libs-->​​
2. ​​<dependency>​​
3. ​​<groupId>net.sf.json-lib</groupId>​​
4. ​​<artifactId>json-lib</artifactId>​​
5. ​​<version>2.4</version>​​
6. ​​<classifier>jdk15</classifier>​​
7. ​​</dependency>​​
8. ​​<dependency>​​
9. ​​<groupId>com.google.code.gson</groupId>​​
10. ​​<artifactId>gson</artifactId>​​
11. ​​<version>2.8.2</version>​​
12. ​​</dependency>​​
13. ​​<dependency>​​
14. ​​<groupId>com.alibaba</groupId>​​
15. ​​<artifactId>fastjson</artifactId>​​
16. ​​<version>1.2.46</version>​​
17. ​​</dependency>​​
18. ​​<dependency>​​
19. ​​<groupId>com.fasterxml.jackson.core</groupId>​​
20. ​​<artifactId>jackson-databind</artifactId>​​
21. ​​<version>2.9.4</version>​​
22. ​​</dependency>​​
23. ​​<dependency>​​
24. ​​<groupId>com.fasterxml.jackson.core</groupId>​​
25. ​​<artifactId>jackson-annotations</artifactId>​​
26. ​​<version>2.9.4</version>​​
27. ​​</dependency>​​

2.2 四个库的工具类

1. ​​FastJsonUtil.javapublic classFastJsonUtil{​​
2. ​​publicstaticString bean2Json(Object obj) {​​
3. ​​return JSON.toJSONString(obj);​​
4. ​​}​​
5.
6. ​​publicstatic<T> T json2Bean(String jsonStr, Class<T> objClass) {​​
7. ​​return JSON.parseObject(jsonStr, objClass);​​
8. ​​}​​
9. ​​}​​
10.
11. ​​GsonUtil.javapublic classGsonUtil{​​
12. ​​privatestaticGson gson = newGsonBuilder().create();​​
13.
14. ​​publicstaticString bean2Json(Object obj) {​​
15. ​​return gson.toJson(obj);​​
16. ​​}​​
17.
18. ​​publicstatic<T> T json2Bean(String jsonStr, Class<T> objClass) {​​
19. ​​return gson.fromJson(jsonStr, objClass);​​
20. ​​}​​
21.
22. ​​publicstaticString jsonFormatter(String uglyJsonStr) {​​
23. ​​Gson gson = newGsonBuilder().setPrettyPrinting().create();​​
24. ​​JsonParser jp = newJsonParser();​​
25. ​​JsonElement je = jp.parse(uglyJsonStr);​​
26. ​​return gson.toJson(je);​​
27. ​​}​​
28. ​​}​​
29.
30. ​​JacksonUtil.javapublic classJacksonUtil{​​
31. ​​privatestaticObjectMapper mapper = newObjectMapper();​​
32.
33. ​​publicstaticString bean2Json(Object obj) {​​
34. ​​try{​​
35. ​​return mapper.writeValueAsString(obj);​​
36. ​​} catch(JsonProcessingException e) {​​
37. ​​e.printStackTrace();​​
38. ​​returnnull;​​
39. ​​}​​
40. ​​}​​
41.
42. ​​publicstatic<T> T json2Bean(String jsonStr, Class<T> objClass) {​​
43. ​​try{​​
44. ​​return mapper.readValue(jsonStr, objClass);​​
45. ​​} catch(IOException e) {​​
46. ​​e.printStackTrace();​​
47. ​​returnnull;​​
48. ​​}​​
49. ​​}​​
50. ​​}​​
51.
52. ​​JsonLibUtil.javapublic classJsonLibUtil{​​
53.
54. ​​publicstaticString bean2Json(Object obj) {​​
55. ​​JSONObject jsonObject = JSONObject.fromObject(obj);​​
56. ​​return jsonObject.toString();​​
57. ​​}​​
58.
59. ​​@SuppressWarnings("unchecked")​​
60. ​​publicstatic<T> T json2Bean(String jsonStr, Class<T> objClass) {​​
61. ​​return(T) JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);​​
62. ​​}​​
63. ​​}​​

2.3 准备Model类

这里我写一个简单的Person类,同时属性有Date、List、Map和自定义的类FullName,最大程度模拟真实场景。


1. ​​publicclassPerson{​​
2. ​​privateString name;​​
3. ​​privateFullName fullName;​​
4. ​​privateint age;​​
5. ​​privateDate birthday;​​
6. ​​privateList<String> hobbies;​​
7. ​​privateMap<String, String> clothes;​​
8. ​​privateList<Person> friends;​​
9.
10. ​​// getter/setter省略​​
11.
12. ​​@Override​​
13. ​​publicString toString() {​​
14. ​​StringBuilder str = newStringBuilder("Person [name="+ name + ", fullName="+ fullName + ", age="​​
15. ​​+ age + ", birthday="+ birthday + ", hobbies="+ hobbies​​
16. ​​+ ", clothes="+ clothes + "]\n");​​
17. ​​if(friends != null) {​​
18. ​​str.append("Friends:\n");​​
19. ​​for(Person f : friends) {​​
20. ​​str.append("\t").append(f);​​
21. ​​}​​
22. ​​}​​
23. ​​return str.toString();​​
24. ​​}​​
25.
26. ​​}​​
27. ​​publicclassFullName{​​
28. ​​privateString firstName;​​
29. ​​privateString middleName;​​
30. ​​privateString lastName;​​
31.
32. ​​publicFullName() {​​
33. ​​}​​
34.
35. ​​publicFullName(String firstName, String middleName, String lastName) {​​
36. ​​this.firstName = firstName;​​
37. ​​this.middleName = middleName;​​
38. ​​this.lastName = lastName;​​
39. ​​}​​
40.
41. ​​// 省略getter和setter​​
42.
43. ​​@Override​​
44. ​​publicString toString() {​​
45. ​​return"[firstName="+ firstName + ", middleName="​​
46. ​​+ middleName + ", lastName="+ lastName + "]";​​
47. ​​}​​
48. ​​}​​

2.4 JSON序列化性能基准测试


1. ​​@BenchmarkMode(Mode.SingleShotTime)​​
2. ​​@OutputTimeUnit(TimeUnit.SECONDS)​​
3. ​​@State(Scope.Benchmark)​​
4. ​​publicclassJsonSerializeBenchmark{​​
5. ​​/**​​
6. ​​* 序列化次数参数​​
7. ​​*/​​
8. ​​@Param({"1000", "10000", "100000"})​​
9. ​​privateint count;​​
10.
11. ​​privatePerson p;​​
12.
13. ​​publicstaticvoid main(String[] args) throwsException{​​
14. ​​Options opt = newOptionsBuilder()​​
15. ​​.include(JsonSerializeBenchmark.class.getSimpleName())​​
16. ​​.forks(1)​​
17. ​​.warmupIterations(0)​​
18. ​​.build();​​
19. ​​Collection<RunResult> results = newRunner(opt).run();​​
20. ​​ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");​​
21. ​​}​​
22.
23. ​​@Benchmark​​
24. ​​publicvoidJsonLib() {​​
25. ​​for(int i = 0; i < count; i++) {​​
26. ​​JsonLibUtil.bean2Json(p);​​
27. ​​}​​
28. ​​}​​
29.
30. ​​@Benchmark​​
31. ​​publicvoidGson() {​​
32. ​​for(int i = 0; i < count; i++) {​​
33. ​​GsonUtil.bean2Json(p);​​
34. ​​}​​
35. ​​}​​
36.
37. ​​@Benchmark​​
38. ​​publicvoidFastJson() {​​
39. ​​for(int i = 0; i < count; i++) {​​
40. ​​FastJsonUtil.bean2Json(p);​​
41. ​​}​​
42. ​​}​​
43.
44. ​​@Benchmark​​
45. ​​publicvoidJackson() {​​
46. ​​for(int i = 0; i < count; i++) {​​
47. ​​JacksonUtil.bean2Json(p);​​
48. ​​}​​
49. ​​}​​
50.
51. ​​@Setup​​
52. ​​publicvoid prepare() {​​
53. ​​List<Person> friends=newArrayList<Person>();​​
54. ​​friends.add(createAPerson("小明",null));​​
55. ​​friends.add(createAPerson("Tony",null));​​
56. ​​friends.add(createAPerson("陈小二",null));​​
57. ​​p=createAPerson("邵同学",friends);​​
58. ​​}​​
59.
60. ​​@TearDown​​
61. ​​publicvoid shutdown() {​​
62. ​​}​​
63.
64. ​​privatePerson createAPerson(String name,List<Person> friends) {​​
65. ​​Person newPerson=newPerson();​​
66. ​​newPerson.setName(name);​​
67. ​​newPerson.setFullName(newFullName("zjj_first", "zjj_middle", "zjj_last"));​​
68. ​​newPerson.setAge(24);​​
69. ​​List<String> hobbies=newArrayList<String>();​​
70. ​​hobbies.add("篮球");​​
71. ​​hobbies.add("游泳");​​
72. ​​hobbies.add("coding");​​
73. ​​newPerson.setHobbies(hobbies);​​
74. ​​Map<String,String> clothes=newHashMap<String, String>();​​
75. ​​clothes.put("coat", "Nike");​​
76. ​​clothes.put("trousers", "adidas");​​
77. ​​clothes.put("shoes", "安踏");​​
78. ​​newPerson.setClothes(clothes);​​
79. ​​newPerson.setFriends(friends);​​
80. ​​return newPerson;​​
81. ​​}​​
82. ​​}​​

说明一下,上面的代码中


1. ​​ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");​​

这个是我自己编写的将性能测试报告数据填充至Echarts图,然后导出png图片的方法,具体代码我就不贴了,参考我的github源码。

执行后的结果图:

Java中常用的JSON库,哪个性能更牛?_开发语言

从上面的测试结果可以看出,序列化次数比较小的时候,Gson性能最好,当不断增加的时候到了100000,Gson明细弱于Jackson和FastJson, 这时候FastJson性能是真的牛,另外还可以看到不管数量少还是多,Jackson一直表现优异。而那个Json-lib简直就是来搞笑的。^_^

2.5 JSON反序列化性能基准测试


1. ​​@BenchmarkMode(Mode.SingleShotTime)​​
2. ​​@OutputTimeUnit(TimeUnit.SECONDS)​​
3. ​​@State(Scope.Benchmark)​​
4. ​​publicclassJsonDeserializeBenchmark{​​
5. ​​/**​​
6. ​​* 反序列化次数参数​​
7. ​​*/​​
8. ​​@Param({"1000", "10000", "100000"})​​
9. ​​privateint count;​​
10.
11. ​​privateString jsonStr;​​
12.
13. ​​publicstaticvoid main(String[] args) throwsException{​​
14. ​​Options opt = newOptionsBuilder()​​
15. ​​.include(JsonDeserializeBenchmark.class.getSimpleName())​​
16. ​​.forks(1)​​
17. ​​.warmupIterations(0)​​
18. ​​.build();​​
19. ​​Collection<RunResult> results = newRunner(opt).run();​​
20. ​​ResultExporter.exportResult("JSON反序列化性能", results, "count", "秒");​​
21. ​​}​​
22.
23. ​​@Benchmark​​
24. ​​publicvoidJsonLib() {​​
25. ​​for(int i = 0; i < count; i++) {​​
26. ​​JsonLibUtil.json2Bean(jsonStr, Person.class);​​
27. ​​}​​
28. ​​}​​
29.
30. ​​@Benchmark​​
31. ​​publicvoidGson() {​​
32. ​​for(int i = 0; i < count; i++) {​​
33. ​​GsonUtil.json2Bean(jsonStr, Person.class);​​
34. ​​}​​
35. ​​}​​
36.
37. ​​@Benchmark​​
38. ​​publicvoidFastJson() {​​
39. ​​for(int i = 0; i < count; i++) {​​
40. ​​FastJsonUtil.json2Bean(jsonStr, Person.class);​​
41. ​​}​​
42. ​​}​​
43.
44. ​​@Benchmark​​
45. ​​publicvoidJackson() {​​
46. ​​for(int i = 0; i < count; i++) {​​
47. ​​JacksonUtil.json2Bean(jsonStr, Person.class);​​
48. ​​}​​
49. ​​}​​
50.
51. ​​@Setup​​
52. ​​publicvoid prepare() {​​
53. ​​jsonStr="{\"name\":\"同学\",\"fullName\":{\"firstName\":\"zjj_first\",\"middleName\":\"zjj_middle\",\"lastName\":\"zjj_last\"},\"age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳\",\"coding\"],\"clothes\":{\"shoes\":\"安踏\",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":[{\"name\":\"小明\",\"fullName\":{\"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\"age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳\",\"coding\"],\"clothes\":{\"shoes\":\"安踏\",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null},{\"name\":\"Tony\",\"fullName\":{\"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\"age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳\",\"coding\"],\"clothes\":{\"shoes\":\"安踏\",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null},{\"name\":\"陈小二\",\"fullName\":{\"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\"age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳\",\"coding\"],\"clothes\":{\"shoes\":\"安踏\",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null}]}";​​
54. ​​}​​
55.
56. ​​@TearDown​​
57. ​​publicvoid shutdown() {​​
58. ​​}​​
59. ​​}​​

执行后的结果图:

Java中常用的JSON库,哪个性能更牛?_json_02

从上面的测试结果可以看出,反序列化的时候,Gson、Jackson和FastJson区别不大,性能都很优异,而那个Json-lib还是来继续搞笑的。

标签:jsonStr,count,Jackson,更牛,json,JSON,Java,friends
From: https://blog.51cto.com/u_14928332/5848467

相关文章

  • 月薪10k,20k,40k的Java工程师,差别到底在哪?
    最近某乎又有了一个热议话题:月薪10k,20k,40k的Java工程师,差别到底在哪?出现这种现象,表面上是每个人所在的岗位、公司、级别不同,本质的原因其实是因为大家的能力不同。不管什么......
  • Java 云原生微服务框架 Quarkus 入门实践
    1.概述1.1定义Quarkus定位要做超声速、亚原子的Java框架,使用最好标准为OpenJDKHotSpot和GraalVM量身定制的KubernetesNativeJava栈;从一开始就是针对Kubernetes设计的云......
  • Java泛型
    Java泛型简介在代码中发现了一个没见过没用过的写法,借此复习一下泛型。publicstatic<T>BaseResponseVo.BaseResponseVoBuilder<T>builder(){returnnewB......
  • 设计模式之【建造者模式】使用java建造者模式优雅创建对象
    文章目录​​什么是建造者模式​​​​一步一步认清建造者模式​​​​1、传统方式创建对象​​​​2、建造者模式创建对象​​​​建造者模式优缺点​​​​建造者模式适用......
  • 一个简单的java awt程序
    现在安卓手机可以java编程了,之前测试了控制台编程是OK的,想测试下gui编程,然后想找个简单的示例测试下都半天找不到,后来自己删删改改弄了一个最简单的,记录一下好以后用:impor......
  • Java可重入锁学习
    概论一个线程获取了某个对象的锁,那么它可以再次获得此对象的锁。这个锁就叫做可重入锁。synchronized就是可重入锁,示例:publicclassLeaningThread{publicstati......
  • MessagePack 和System.Text.Json 序列号 反序列化对比
    本博客将测试MessagePack和System.Text.Json序列号反序列化性能项目文件:Program.cs代码:usingBenchmarkDotNet.Running;usingDemo;varsummary=BenchmarkRun......
  • 如何设置JavaScript的版本为6
    如何设置JavaScript的版本为6设置里面搜索JavaScript,语言和框架——>JavaScript 使用JavaScript6的好处例如:for循环中可以使用let而不用var//这里出现let是因为Jav......
  • Java反应式编程(1)
    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~ 前面把Java函数式编程的由来和最主要的核心知识点讲完了。包括比较难懂的Lambda表达式是怎么演变而来的也全部都撸了一......
  • JavaWeb-新版
    JavaWeb参考文章:https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/01、Web基础概念简介1、服务器与客户端线下的服务器与客户端......