Java ObjectOutputStream序列化與JSON序列化大比拼
一、背景
有專案需要傳輸Map結構的資料,有人傾向用Java序列化來做,有人傾向用JSON的序列化來做。所以我們還是比比吧。
Java觀點:Object2Object,使用時簡單快速。
JSON觀點:JSON格式與語言無關,擴充套件性強,速度也應該不慢。
大家可能對Java序列化都有一個錯誤的認識,認為Java序列化比JSON的序列化效率高並且序列化的資料小,其實實際上並不一定是這樣,我這次就想通過實際測試來解開這個謎團。
二、測試方式
測試同一個Map<String,Object>並序列化為byte[],並再將byte[]反序列化為Map<String,Object>的過程。Object中包括String,Integer,Long,Boolean,Float,Double常規型別的資料。
序列化:Map<String,Object> -> byte[]
反序列化:byte[] -> Map<String,Object>
測試各種大小不同的Map,並迴圈執行同一操作N次,來得到一個相對穩定的線性結果。
三、比較的物件
JAVA:
手寫Java(1.6.0_32)與Common Lang3(3.1)的SerializationUtils。
JSON:
將採用Gson(2.2.2)與json-smart(2.0-RC2)兩種不同的JSON解析器。json-smart號稱是速度最快的JSON解析器。
四、比較結果
Map大小(10-100)迴圈10萬次
序列化時間比較(y為序列化時間ms)
反序列化時間比較(y為反序列化時間ms)
序列化時間彙總比較(y為序列化與反序列化總時間ms)
序列化後byte大小比較(由於同類線重合顯示為2條線)
Map大小(100-1000)迴圈1萬次
序列化時間比較(y為序列化時間ms)
反序列化時間比較(y為反序列化時間ms)
序列化時間彙總比較(y為序列化與反序列化總時間ms)
序列化後byte大小比較(由於同類線重合顯示為2條線)
比較總結
Map在小於100時:
Java的反序列化時的效能要比Java序列化時效能差很多,1.5倍左右差距。
JSON序列化效能明顯由於Java序列化效能,尤其是反序列化過程。並且序列化後的資料大小也是JSON格式的小。
Map在大於100小於1000時:
Java的反序列化時的效能並沒有隨Map的大小變化而變差。
JSON陣營中Gson在序列化過程中,比Java只快了那麼一點點。在反序列化過程中Gson開始領先與Java,但在Map的大小過700多以後,Gson的反序列化效能比Java要慢。但JSON陣營中的json-smart依然表現出色完全是兩個級別。
並不是Java的序列化速度總是最快體積最小,Java需要考慮物件型別,屬性型別與內部物件資訊等一系列對資料本身並不相關的內容的處理。JSON以固定的格式,穩定簡單的資料結構大大簡化了序列化過程,雖然也要建立新的Java資料物件但並不會比Java反序列化的速度慢。
從測試結果上看JSON的json-smart更適合專案的需要。
五、測試程式碼原始碼
SerializationTest介面
-
package org.noahx.javavsjson;
-
import java.util.Map;
-
/**
-
* Created with IntelliJ IDEA.
-
* User: noah
-
* Date: 3/8/13
-
* Time: 9:59 PM
-
* To change this template use File | Settings | File Templates.
-
*/
-
public interface SerializationTest {
-
public String getTestName();
-
public Map<String, Object> testBytes2Map(byte[] bytes);
-
public byte[] testMap2Bytes(Map<String, Object> map);
-
}
JavaSerializationTest
-
package org.noahx.javavsjson;
-
import java.io.*;
-
import java.util.Map;
-
/**
-
* Created with IntelliJ IDEA.
-
* User: noah
-
* Date: 3/8/13
-
* Time: 10:05 PM
-
* To change this template use File | Settings | File Templates.
-
*/
-
public class JavaSerializationTest implements SerializationTest {
-
@Override
-
public String getTestName() {
-
return "Java";
-
}
-
@Override
-
public Map<String, Object> testBytes2Map(byte[] bytes) {
-
Map<String, Object> result = null;
-
try {
-
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
-
ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
-
result = (Map<String, Object>) inputStream.readObject();
-
inputStream.close();
-
} catch (ClassNotFoundException e) {
-
e.printStackTrace();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
return result;
-
}
-
@Override
-
public byte[] testMap2Bytes(Map<String, Object> map) {
-
byte[] bytes = null;
-
try {
-
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-
ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
-
outputStream.writeObject(map);
-
outputStream.close();
-
bytes = byteArrayOutputStream.toByteArray();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
return bytes;
-
}
-
}
CommonLang3SerializationTest
-
package org.noahx.javavsjson;
-
import org.apache.commons.lang3.SerializationUtils;
-
import java.io.Serializable;
-
import java.util.Map;
-
/**
-
* Created with IntelliJ IDEA.
-
* User: noah
-
* Date: 3/9/13
-
* Time: 2:24 AM
-
* To change this template use File | Settings | File Templates.
-
*/
-
public class CommonLang3SerializationTest implements SerializationTest {
-
@Override
-
public String getTestName() {
-
return "Commons Lang3";
-
}
-
@Override
-
public Map<String, Object> testBytes2Map(byte[] bytes) {
-
return (Map<String, Object>) SerializationUtils.deserialize(bytes);
-
}
-
@Override
-
public byte[] testMap2Bytes(Map<String, Object> map) {
-
return SerializationUtils.serialize((Serializable) map);
-
}
-
}
GsonSerializationTest
-
package org.noahx.javavsjson;
-
import com.google.gson.Gson;
-
import java.io.UnsupportedEncodingException;
-
import java.util.Map;
-
/**
-
* Created with IntelliJ IDEA.
-
* User: noah
-
* Date: 3/8/13
-
* Time: 10:02 PM
-
* To change this template use File | Settings | File Templates.
-
*/
-
public class GsonSerializationTest implements SerializationTest {
-
private Gson gson;
-
public GsonSerializationTest() {
-
gson = new Gson();
-
}
-
@Override
-
public String getTestName() {
-
return "Gson";
-
}
-
@Override
-
public Map<String, Object> testBytes2Map(byte[] bytes) {
-
Map<String, Object> result = null;
-
try {
-
result = gson.fromJson(new String(bytes, "UTF-8"), Map.class);
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
}
-
return result;
-
}
-
@Override
-
public byte[] testMap2Bytes(Map<String, Object> map) {
-
String str = gson.toJson(map);
-
byte[] bytes = null;
-
try {
-
bytes = str.getBytes("UTF-8");
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
}
-
return bytes;
-
}
-
}
JsonSmartSerializationTest
-
package org.noahx.javavsjson;
-
import net.minidev.json.JSONObject;
-
import net.minidev.json.JSONValue;
-
import net.minidev.json.parser.ParseException;
-
import java.io.UnsupportedEncodingException;
-
import java.util.Map;
-
/**
-
* Created with IntelliJ IDEA.
-
* User: noah
-
* Date: 3/9/13
-
* Time: 1:30 AM
-
* To change this template use File | Settings | File Templates.
-
*/
-
public class JsonSmartSerializationTest implements SerializationTest {
-
@Override
-
public String getTestName() {
-
return "Json Smart";
-
}
-
@Override
-
public Map<String, Object> testBytes2Map(byte[] bytes) {
-
Map<String, Object> map = null;
-
try {
-
map = (Map<String, Object>) JSONValue.parseStrict((new String(bytes, "UTF-8")));
-
} catch (ParseException e) {
-
e.printStackTrace();
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
}
-
return map;
-
}
-
@Override
-
public byte[] testMap2Bytes(Map<String, Object> map) {
-
String str = JSONObject.toJSONString(map);
-
byte[] result = null;
-
try {
-
result = str.getBytes("UTF-8");
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
}
-
return result;
-
}
-
}
原始碼下載:http://sdrv.ms/12ECmgG
P.S.
我也測試過Map<String,String>固定資料型別value只為String的情況,這時Java與JSON的效能的差距會減小,但JSON序列化效能與資料大小還是佔優勢,尤其是反序列化的速度JSON更出色。
Gson在數值反序列化後,因為Object無法確定型別,Map中的Long,Integer,Float統一轉為了Double型別。
json-smart不一樣,如果整數超過Integer的範圍轉Long,沒有超過轉Integer。浮點Float轉為Double型別。