常见的json解析有原生的JSONObject和JSONArray方法,谷歌的GSON库,阿里的fastjson,还有jackson,json-lib。
Json-lib(项目地址:http://json-lib.sourceforge.net/index.html)。json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括commons-beanutils.jar,commons-collections-3.2.jar,commons-lang-2.6.jar,commons-logging-1.1.1.jar,ezmorph-1.0.6.jar,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷,比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能满足现在互联网化的需求。 ##1、java方法解析
JSONObject解析json对象
JSONArray解析json数组 例如json字符串为:
{ "personData": [ { "age": 12, "name": "nate", "schoolInfo": [ { "School_name": "清华" }, { "School_name": "北大" } ], "url": "http://pic.yesky.com/uploadImages/2014/345/36/E8C039MU0180.jpg" }, { "age": 24, "name": "jack", ··· } ], "result": 1 }
分析这段json数据,
- 第一层是一个花括号括号,即jsonObect对象,然后这个对象里面有一个personData的JSONArray数组,以及一个result属性
- 第二层personData的JSONArray数组,它里面除了属性之外,还有一个schoolInfo的JSONArray数组
- 第三次是schoolInfo的JSONArray数组里面的JSONObject对象
解析:
public class Httpjson extends Thread {
private String url;
private Context context;
private ListView listView;
private JsonAdapter adapter;
private Handler handler;
public Httpjson(String url, ListView listView, JsonAdapter adapter, Handler handler) {
super();
this.url = url;
this.listView = listView;
this.adapter = adapter;
this.handler = handler;
}
@Override
public void run() {
URL httpUrl;
try {
httpUrl = new URL(url);
···
}
/**
* 从网络中获取JSON字符串,然后解析
* @param json
* @return
*/
private List<Person> jsonParse(String json) {
try {
List<Person> personlist = new ArrayList<Person>();
JSONObject jsonObject = new JSONObject(json);
int result = jsonObject.getInt("result");
if (result == 1) {
JSONArray jsonArray = jsonObject.getJSONArray("personData");
for (int i = 0; i < jsonArray.length(); i++) {
Person person = new Person();
JSONObject personData = jsonArray.getJSONObject(i);
int age = personData.getInt("age");
String url = personData.getString("url");
String name = personData.getString("name");
···
JSONArray schoolInfoArray = personData.getJSONArray("schoolInfo");
for (int j = 0; j < schoolInfoArray.length(); j++) {
JSONObject schoolInfojson = schoolInfoArray.getJSONObject(j);
String schoolName = schoolInfojson.getString("School_name");
···
}
···
}
return personlist;
} else {
Toast.makeText(context, "erro", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
Log.e("JsonParseActivity", "json解析出现了问题");
}
return null;
}
}
##2、gson解析 ####(1)简介 GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。
####(2)特点
- 快速、高效
- 代码量少、简洁
- 面向对象
- 数据传递和解析方便
####(3)编写bean类 要写出能让gson使用的bean类,其中的key也就是名字,如date、safe这些必须一一对应起来。其次就是在bean类中,遇到花括号就写一个class类,遇到方括号就写一个Arraylist数组。这些就是主要规则了!内部的class类写成内部内的形式。
内部嵌套的类必须是static的,要不然解析会出错;
类里面的属性名必须跟Json字段里面的Key是一模一样的;
内部嵌套的用[]括起来的部分是一个List,所以定义为 public List b,而只用{}嵌套的就定义为 public C c,
{ "date": "2014-04-23", ···
"name": "蘑菇街", "packageName": "com.mogujie", "safe": [ { "safeDes": "已通过安智市场官方认证,是正版软件", ··· }, { "safeDes": "已通过安智市场安全检测,请放心使用", ··· }, { "safeDes": "无任何形式的广告", ··· } ], "screen": [ "app/com.mogujie/screen0.jpg", ··· ], "size": 6746678, ··· }public class GsonParseMoGuBean {
public String data; public String name; public String packageName; ··· public ArrayList<SafeInfo> safe; public class SafeInfo { public String safeDes; ··· } public ArrayList<String> screen;
}
####(4)将json格式的字符串{}解析为java对象
Java对象
/**
* //将json格式的字符窜{}转换为java对象
*/
private void jsonToJavaObjectByGson() {
//1获取或创建json数据
String json ="{\n" +
"\t\"id\":2, \"name\":\"大虾\", \n" +
"\t\"price\":12.3, \n" +
"\t\"imagePath\":\"http://192.168.10.165:8080/L05_Server/images/f1.jpg\"\n" +
"}\n";
//2解析json数据
Gson gson =new Gson();
//第一个参数是要解析的数据,第二个参数是解析生成的java对象的类
ShopInfo shopInfo = gson.fromJson(json, ShopInfo.class);
}
####(5)将json格式的字符串{}解析为java对象的list
private void jsonToJavaListByGson() {
//1获取或创建json数据
String json = "[\n" +
" {\n" +
" \"id\": 1,\n" +
" \"imagePath\": \"http://192.168.10.165:8080/f1.jpg\",\n" +
" \"name\": \"大虾 1\",\n" +
" \"price\": 12.3\n" + " },\n" + " {\n" +
" \"id\": 2,\n" +
" \"imagePath\": \"http://192.168.10.165:8080/f2.jpg\",\n" +
" \"name\": \"大虾 2\",\n" +
" \"price\": 12.5\n" + " }\n" +
"]";
//2解析json数据
Gson gson =new Gson();
//List<ShopInfo>:是要返回数据的集合
List<ShopInfo> shops = gson.fromJson(json,new TypeToken<List<ShopInfo>>(){}.getType());
//3显示数据
tv_gson_orignal.setText(json);
tv_gson_last.setText(shops.toString());
}
####(6)将java对象转换为json字符串
private void javaToJSONByGson() {
//1获取或创建java数据
ShopInfo shopInfo = new ShopInfo(1,"鲍鱼",250.0,"baoyu");
//2生成json数据
Gson gson = new Gson();
String json = gson.toJson(shopInfo);
//3显示数据
tv_gson_orignal.setText(shopInfo.toString());
tv_gson_last.setText(json);
}
####(7)将java对象的list转换为json字符串[]
/**
* //将java对象的list转换为json字符窜
*/
private void javaToJSONArrayByGson() {
//1获取或创建java数据
List<ShopInfo> shops =new ArrayList<ShopInfo>();
ShopInfo baoyu = new ShopInfo(1,"鲍鱼",250.0,"baoyu");
ShopInfo longxia = new ShopInfo(1,"龙虾",250.0,"longxia");
shops.add(baoyu);
shops.add(longxia);
//2生成json数据
Gson gson = new Gson();
String json = gson.toJson(shops);
//3显示数据
tv_gson_orignal.setText(shops.toString());
tv_gson_last.setText(json);
}
##3、fastjson ####(1)简介 在日常的java项目开发中,JSON的使用越来越频繁,对于Json的处理工具也有很多。接下来就介绍一下阿里开源的一个高性能的JSON框架FastJson,功能完善,完全支持标准JSON库,现在已经越来越受到开发者的青睐。
####(2)特点 Fastjson 是一个 Java 语言编写的高性能功能完善的 JSON 库。它采用一种“假定有序快速匹配”的算法,把JSONParse的性能提升到极致,是目前Java语言中最快的JSON库。
####(4)将 json 格式的字符串{}转换为 Java 对象
private void jsonToJavaObjectByFastJson() {
// 1 获取或创建 JSON 数据
String json = "{\n" +
"\t\"id\":2, \"name\":\"大虾\", \n" +
"\t\"price\":12.3, \n" +
"\t\"imagePath\":\"http://192.168.10.165:8080/L05_Server/images/f1.jpg\ "\n" +
"}\n";
// 2 解析 JSON 数据
ShopInfo shopInfo = JSON.parseObject(json, ShopInfo.class);
}
####(4)将 json 格式的字符串[]转换为 Java 对象的 List
private void jsonToJavaListByFastJson() {
// 1 获取或创建 JSON 数据
String json = "[\n" +
" {\n"+
" \"id\": 1,\n" +
" \"imagePath\":
\"http://192.168.10.165:8080/f1.jpg\",\n" +
" " " " " "
\"name\": \"大虾 1\",\n" +
\"price\": 12.3\n" + },\n" +
{\n"+
\"id\": 2,\n" + \"imagePath\":
\"http://192.168.10.165:8080/f2.jpg\",\n" +
" \"name\": \"大虾 2\",\n" +
" \"price\": 12.5\n" + " }\n"+
"]";
// 2 解析 JSON 数据
List<ShopInfo> shopInfos = JSON.parseArray(json, ShopInfo.class);
}
####(5)将 Java 对象转换为 json 字符串
private void javaToJsonObjectByFastJson() {
// 1 获取 Java 对象
ShopInfo shopInfo = new ShopInfo(1, "鲍鱼", 250.0, "baoyu");
// 2 生成 JSON 数据
String json = JSON.toJSONString(shopInfo);
// 3 数据显示 tv_fastjson_orignal.setText(shopInfo.toString()); tv_fastjson_last.setText(json);
}
####(7)将 Java 对象的 List 转换为 json 字符串[]
private void javaToJsonArrayByFastJson() {
// 1 获取 Java 集合
List<ShopInfo> shops = new ArrayList<>();
ShopInfo baoyu = new ShopInfo(1, "鲍鱼", 250.0, "baoyu");
ShopInfo longxia = new ShopInfo(2, "龙虾", 251.0, "longxia"); shops.add(baoyu);
shops.add(longxia);
// 2 生成 JSON 数据
String json = JSON.toJSONString(shops);
// 3 数据显示 tv_fastjson_orignal.setText(shops.toString()); tv_fastjson_last.setText(json);
}
##4、性能对比
选择一个合适的JSON库要从多个方面进行考虑:
- 字符串解析成JSON性能
- 字符串解析成JavaBean性能
- JavaBean构造JSON性能
- 集合构造JSON性能
- 易用性 编写性能测试 接下来开始编写这四个库的性能测试代码。
####(1)添加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>
####(2)四个库的工具类
java 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);
}
}
java 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);
}
}
java 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;
}
}
}
java 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);
}
}
####(3)准备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省略
@Override
public 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
@Override
public String toString() {
return "[firstName=" + firstName + ", middleName="
+ middleName + ", lastName=" + lastName + "]";
}
}
####(4)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", "秒");
}
@Benchmark
public void JsonLib() {
for (int i = 0; i < count; i++) {
JsonLibUtil.bean2Json(p);
}
}
@Benchmark
public void Gson() {
for (int i = 0; i < count; i++) {
GsonUtil.bean2Json(p);
}
}
@Benchmark
public void FastJson() {
for (int i = 0; i < count; i++) {
FastJsonUtil.bean2Json(p);
}
}
@Benchmark
public void Jackson() {
for (int i = 0; i < count; i++) {
JacksonUtil.bean2Json(p);
}
}
@Setup
public void prepare() {
List<Person> friends=new ArrayList<Person>();
friends.add(createAPerson("小明",null));
friends.add(createAPerson("Tony",null));
friends.add(createAPerson("陈小二",null));
p=createAPerson("邵同学",friends);
}
@TearDown
public 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简直就是来搞笑的。^_^
####(5)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", "秒");
}
@Benchmark
public void JsonLib() {
for (int i = 0; i < count; i++) {
JsonLibUtil.json2Bean(jsonStr, Person.class);
}
}
@Benchmark
public void Gson() {
for (int i = 0; i < count; i++) {
GsonUtil.json2Bean(jsonStr, Person.class);
}
}
@Benchmark
public void FastJson() {
for (int i = 0; i < count; i++) {
FastJsonUtil.json2Bean(jsonStr, Person.class);
}
}
@Benchmark
public void Jackson() {
for (int i = 0; i < count; i++) {
JacksonUtil.json2Bean(jsonStr, Person.class);
}
}
@Setup
public 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}]}";
}
@TearDown
public void shutdown() {
}
}
执行后的结果图:
从上面的测试结果可以看出,反序列化的时候,Gson、Jackson和FastJson区别不大,性能都很优异,而那个Json-lib还是来继续搞笑的。
转载声明:性能比较部分由客由熊能创作 © 飞污熊博客。