绝了,几款主流的 JSON 库性能对比!

本篇通过JMH(Oracle官方测试框架)来测试一下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. 易用性

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

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解析的神器。

FastJson

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

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

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的介绍这么长啊?因为它也是本人的最爱。

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在功能和性能上面都不能满足现在互联网化的需求。

编写性能测试

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

添加maven依赖

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

<!-- Json libs-->
<dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier>
</dependency>
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.2</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.46</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.4</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.4</version>
</dependency>

四个库的工具类

FastJsonUtil.java

public class FastJsonUtil {public static String bean2Json(Object obj) {return JSON.toJSONString(obj);}public static <T> T json2Bean(String jsonStr, Class<T> objClass) {return JSON.parseObject(jsonStr, objClass);}
}

GsonUtil.java

public class GsonUtil {private static Gson gson = new GsonBuilder().create();public static String bean2Json(Object obj) {return gson.toJson(obj);}public static <T> T json2Bean(String jsonStr, Class<T> objClass) {return gson.fromJson(jsonStr, objClass);}public static String jsonFormatter(String uglyJsonStr) {Gson gson = new GsonBuilder().setPrettyPrinting().create();JsonParser jp = new JsonParser();JsonElement je = jp.parse(uglyJsonStr);return gson.toJson(je);}
}

JacksonUtil.java

public class JacksonUtil {private static ObjectMapper mapper = new ObjectMapper();public static String bean2Json(Object obj) {try {return mapper.writeValueAsString(obj);} catch (JsonProcessingException e) {e.printStackTrace();return null;}}public static <T> T json2Bean(String jsonStr, Class<T> objClass) {try {return mapper.readValue(jsonStr, objClass);} catch (IOException e) {e.printStackTrace();return null;}}
}

JsonLibUtil.java

public class JsonLibUtil {public static String bean2Json(Object obj) {JSONObject jsonObject = JSONObject.fromObject(obj);return jsonObject.toString();}@SuppressWarnings("unchecked")public static <T> T json2Bean(String jsonStr, Class<T> objClass) {return (T) JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);}
}

准备Model类

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

public class Person {private String name;private FullName fullName;private int age;private Date birthday;private List<String> hobbies;private Map<String, String> clothes;private List<Person> friends;// getter/setter省略@Overridepublic String toString() {StringBuilder str = new StringBuilder("Person [name=" + name + ", fullName=" + fullName + ", age="+ age + ", birthday=" + birthday + ", hobbies=" + hobbies+ ", clothes=" + clothes + "]\n");if (friends != null) {str.append("Friends:\n");for (Person f : friends) {str.append("\t").append(f);}}return str.toString();}}
public class FullName {private String firstName;private String middleName;private String lastName;public FullName() {}public FullName(String firstName, String middleName, String lastName) {this.firstName = firstName;this.middleName = middleName;this.lastName = lastName;}// 省略getter和setter@Overridepublic String toString() {return "[firstName=" + firstName + ", middleName="+ middleName + ", lastName=" + lastName + "]";}
}

JSON序列化性能基准测试

@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class JsonSerializeBenchmark {/*** 序列化次数参数*/@Param({"1000", "10000", "100000"})private int count;private Person p;public static void main(String[] args) throws Exception {Options opt = new OptionsBuilder().include(JsonSerializeBenchmark.class.getSimpleName()).forks(1).warmupIterations(0).build();Collection<RunResult> results =  new Runner(opt).run();ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");}@Benchmarkpublic void JsonLib() {for (int i = 0; i < count; i++) {JsonLibUtil.bean2Json(p);}}@Benchmarkpublic void Gson() {for (int i = 0; i < count; i++) {GsonUtil.bean2Json(p);}}@Benchmarkpublic void FastJson() {for (int i = 0; i < count; i++) {FastJsonUtil.bean2Json(p);}}@Benchmarkpublic void Jackson() {for (int i = 0; i < count; i++) {JacksonUtil.bean2Json(p);}}@Setuppublic void prepare() {List<Person> friends=new ArrayList<Person>();friends.add(createAPerson("小明",null));friends.add(createAPerson("Tony",null));friends.add(createAPerson("陈小二",null));p=createAPerson("邵同学",friends);}@TearDownpublic void shutdown() {}private Person createAPerson(String name,List<Person> friends) {Person newPerson=new Person();newPerson.setName(name);newPerson.setFullName(new FullName("zjj_first", "zjj_middle", "zjj_last"));newPerson.setAge(24);List<String> hobbies=new ArrayList<String>();hobbies.add("篮球");hobbies.add("游泳");hobbies.add("coding");newPerson.setHobbies(hobbies);Map<String,String> clothes=new HashMap<String, String>();clothes.put("coat", "Nike");clothes.put("trousers", "adidas");clothes.put("shoes", "安踏");newPerson.setClothes(clothes);newPerson.setFriends(friends);return newPerson;}
}

说明一下,上面的代码中

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

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

执行后的结果图:

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

JSON反序列化性能基准测试

@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class JsonDeserializeBenchmark {/*** 反序列化次数参数*/@Param({"1000", "10000", "100000"})private int count;private String jsonStr;public static void main(String[] args) throws Exception {Options opt = new OptionsBuilder().include(JsonDeserializeBenchmark.class.getSimpleName()).forks(1).warmupIterations(0).build();Collection<RunResult> results =  new Runner(opt).run();ResultExporter.exportResult("JSON反序列化性能", results, "count", "秒");}@Benchmarkpublic void JsonLib() {for (int i = 0; i < count; i++) {JsonLibUtil.json2Bean(jsonStr, Person.class);}}@Benchmarkpublic void Gson() {for (int i = 0; i < count; i++) {GsonUtil.json2Bean(jsonStr, Person.class);}}@Benchmarkpublic void FastJson() {for (int i = 0; i < count; i++) {FastJsonUtil.json2Bean(jsonStr, Person.class);}}@Benchmarkpublic void Jackson() {for (int i = 0; i < count; i++) {JacksonUtil.json2Bean(jsonStr, Person.class);}}@Setuppublic void prepare() {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}]}";}@TearDownpublic void shutdown() {}
}

执行后的结果图:

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

作者:熊能
www.xncoding.com/2018/01/09/java/jsons.html往期推荐链表竟然比数组慢这么多?(动图+性能评测)局部变量竟然比全局变量快5倍?关注下方二维码,每一天都有干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545961.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DWZ使用笔记

DWZ使用笔记 一、前言 在近期的一个项目中&#xff0c;引入了DWZ这个富client框架&#xff0c;算是一次尝试吧。期间也遇到不少问题&#xff0c;总算一一攻克了。特以此文记之。本人用的是dwz-ria-1.4.5Asp.net webform&#xff0c;写这篇笔记时最新版本号已经是1.4.6了。DWZ官…

Dynamic_Performance_Tables_not_accessible_问题_解决不能动态统计

Dynamic Performance Tables not accessible, Automatic Statistics Disabled for this session You can disable statistics in the preference menu,or obtanin select priviliges on the v$session,v$sesstat and v$statname tables第一种处理方法&#xff08;不推荐&#x…

ruby三元操作符_在Ruby中使用操作符将元素添加到数组实例中

ruby三元操作符In the previous articles, we have gone through ways through which we can create Array instances. Some of them were Public instance methods and some were Public class methods. We should also know how they both differ from each other. Now we kn…

阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?

最近&#xff0c;无论是读者群&#xff0c;还是公众号后台&#xff0c;很多人都比较关注以下几个问题&#xff1a;阿里的简历是半年只能投递一次吗&#xff1f;阿里的面试可以多个部门同时进行吗&#xff1f;面试没过&#xff0c;又被系统捞起来了&#xff0c;我该怎么办&#…

c语言给定一个非空整数数组_C程序检查给定整数的所有位是否为一(1)

c语言给定一个非空整数数组Problem statement: Write a C Program to check if all the bits of a given integer is one (1). 问题陈述&#xff1a;编写一个C程序来检查给定整数的所有位是否都是一(1) 。 Solution: We can use bitwise operator here to solve the problem. …

记一次蚂蚁金服面试被虐经历

本文来自作者投稿&#xff0c;原作者&#xff1a;yes面试前的小姐姐来说说前不久蚂蚁金服一面的情况。说来也是巧合&#xff0c;当时在群里有位蚂蚁金服的小姐姐发了个内推&#xff0c;看了下JD感觉可以试试于是就私聊了小姐姐发简历内推了。我16年也就是大三上就开始实习了&am…

本地连接和音量图标显示

一种&#xff1a;“控制面板”——“声音和音频设备”——“将音量图标放入任务栏”曾经手动关掉了。只要打开就行了。 第二种&#xff1a;“将音量图标放入任务栏”打勾&#xff0c;无效。丢失sndvol32.exe&#xff0c;文件路径C:\WINDOWS\system32&#xff0c;可以在别的机子…

用python + openpyxl处理excel(07+)文档 + 一些中文处理的技巧

2019独角兽企业重金招聘Python工程师标准>>> 寻觅工具 确定任务之后第一步就是找个趁手的库来干活。 Python Excel上列出了xlrd、xlwt、xlutils这几个包&#xff0c;但是 它们都比较老&#xff0c;xlwt甚至不支持07版以后的excel它们的文档不太友好&#xff0c;都可…

Spring Boot 2.3.3 正式发布!

Spring Boot 2.3.3 稳定版已发布&#xff0c;可从 repo.spring.io 和 Maven Central 获取。<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</versio…

木板最优切割利润最大_最多进行K笔交易的股票最大买卖利润

木板最优切割利润最大This is a very popular interview problem to find maximum profit in stock buying and selling with at most K transactions. This problem has been featured in the interview rounds of Amazon. 这是一个非常受欢迎的面试问题&#xff0c;目的是在最…

禁止访问磁盘的注册表

百度的了一个禁止访问磁盘的注册表问题怎么禁止访问磁盘&#xff0c;手动操作就会&#xff0c;可是有好几十台啊。手动搞&#xff0c;那个累啊。求个高手&#xff0c;帮我弄个注册表或者BAT文件执行都可以&#xff0c;禁止访问D盘跟E盘。网上找了很多资料&#xff0c;都叫用工具…

C语言文本文件与二进制文件转换

本程序要自己创建个文本格式的输入文件a1.txt&#xff0c;编译后能将文本文件前255字节以内的字符转换成相应的AscII码值的二进制表示&#xff0c;并存入输出文件a2.txt中。然后再将二进制文件还原并存入a3.txt文件。实现文件之间的转换。 具体代码如下&#xff1a; #include …

[数据库]Oracle和mysql中的分页总结

Mysql中的分页物理分页•在sql查询时&#xff0c;从数据库只检索分页需要的数据•通常不同的数据库有着不同的物理分页语句•mysql物理分页&#xff0c;采用limit关键字•例如&#xff1a;检索11-20条 select * from user limit 10,10 ;* 每次只查询10条记录.当点击下一页的时候…

List 集合去重的 3 种方法

问题由来在实际开发的时候&#xff0c;我们经常会碰到这么一个困难&#xff1a;一个集合容器里面有很多重复的对象&#xff0c;里面的对象没有主键&#xff0c;但是根据业务的需求&#xff0c;实际上我们需要根据条件筛选出没有重复的对象。比较暴力的方法&#xff0c;就是根据…

c printf 段错误_错误:预期声明在C中的printf之前指定

c printf 段错误The main cause of this error is - missing opening curly brace ({), before the printf() function. 导致此错误的主要原因是-在printf()函数之前缺少打开的花括号( { )。 Example: 例&#xff1a; #include <stdio.h>int main(void)printf("He…

常用的60招电脑操作

1、如果同时有多个窗口打开&#xff0c;想要关闭的话&#xff0c;可以按住shift不放然后点击窗口右上角的关闭图标。2、在保存网页前&#xff0c;可以按一下"ESC"键(或脱机工作)再保存&#xff0c;这样保存很快 3、用电脑听CD可以不用任何的播放软件&#xff0c;把音…

C语言入门——排序

排序的方法有很多种比较常见的便为&#xff1a;冒泡排序、选择排序、插入排序、快速排序。 今天我们就围绕着四种排序来说&#xff0c;如果有兴趣的话可以去查找一下其他排序。 在排序这方面我们主要讨论&#xff1a; 稳定&#xff1a;如果a原本在b前面&#xff0c;而ab&…

【转】eclipse技巧1

2019独角兽企业重金招聘Python工程师标准>>> 俗话说的好啊&#xff0c;“工于利启事&#xff0c;必先善其器”&#xff0c;如果说你的编程功底是一个枪法的话&#xff0c;那么强大的eclipse就是android战士们最好的武器。 这里&#xff0c;我们来总结eclipse的使用技…

Java LinkedList公共int indexOf(Object o)方法(带示例)

LinkedList公共int indexOf(Object o)方法 (LinkedList public int indexOf(Object o) method) This method is available in package java.util.LinkedList.indexOf(Object o). 软件包java.util.LinkedList.indexOf(Object o)中提供了此方法。 This method is used to return …

定时任务最简单的3种实现方法(超好用)

这是我的第 86 篇原创文章作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;定时任务在实际的开发中特别常见&#xff0c;比如电商平台 30 分钟后自动取消未支付的订单&#x…