java中常見的json解析方法、庫以及性能對比

常見的json解析有原生的JSONObject和JSONArray方法,谷歌的GSON庫,阿里的fastjson,還有jackson,json-lib。html

{
    "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數據,java

  • 第一層是一個花括號括號,即jsonObect對象,而後這個對象裏面有一個personData的JSONArray數組,以及一個result屬性
  • 第二層personData的JSONArray數組,它裏面除了屬性以外,還有一個schoolInfo的JSONArray數組
  • 第三次是schoolInfo的JSONArray數組裏面的JSONObject對象

解析:git

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;
    }
}

##二、gson解析 ####(1)簡介   GSON是Google提供的用來在Java對象和JSON數據之間進行映射的Java類庫。能夠將一個Json字符轉成一個Java對象,或者將一個Java轉化爲Json字符串。github

####(2)特色算法

  • 快速、高效
  • 代碼量少、簡潔
  • 面向對象
  • 數據傳遞和解析方便

####(3)編寫bean類 要寫出能讓gson使用的bean類,其中的key也就是名字,如date、safe這些必須一一對應起來。其次就是在bean類中,遇到花括號就寫一個class類,遇到方括號就寫一個Arraylist數組。這些就是主要規則了!內部的class類寫成內部內的形式。json

  • 內部嵌套的類必須是static的,要否則解析會出錯;
  • 類裏面的屬性名必須跟Json字段裏面的Key是如出一轍的;
  • 內部嵌套的用[]括起來的部分是一個List,因此定義爲 public List<B> 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字符串[]app

/**
     * //將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);
    }

##三、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);
}

##四、性能對比

選擇一個合適的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仍是來繼續搞笑的。

轉載聲明:性能比較部分由客由熊能創做 © 飛污熊博客。

相關文章
相關標籤/搜索