I will show you how to customize Java serialization (Externalization), performance comparison default serialization vs my externalization implmentation in this post.
In the most cases, you don't have to care about the serialization performance of default implementation.
But the default implementation uses reflection so it might be a problem if you develop performance critical application.
Here is the example code - simple pojo class and TreeMap which implements Externalizable.
The result, which is tested on my local windows machine, is below. Measuring the time for 1000000 iteration of serialization
Just for your reference, my testing enviroment is below
Here is my testing code and the SerializableClass which implements Serializable and has the same functionality with ExternalizableClass.
In the most cases, you don't have to care about the serialization performance of default implementation.
But the default implementation uses reflection so it might be a problem if you develop performance critical application.
Externalizable
Implement your own serialization is very simple. Just implements Externailizable interface into the class.Here is the example code - simple pojo class and TreeMap which implements Externalizable.
package com.dukesoftware.demos.externalizable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.List; public class ExternalizableClass implements Externalizable{ private String field1; private Double field2; private List<String> field3; public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public Double getField2() { return field2; } public void setField2(Double field2) { this.field2 = field2; } public List<String> getField3() { return field3; } public void setField3(List<String> field3) { this.field3 = field3; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(field1); out.writeDouble(field2); writeExternalCollection(out, field3); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { field1 = (String)in.readObject(); field2 = in.readDouble(); field3 = new ArrayList<>(); readExternalCollection(in, field3); } private static <T> void writeExternalCollection(ObjectOutput out, List<T> c) throws IOException { if(c == null) { out.writeInt(-1); } else { out.writeInt(c.size()); for(T elem : c){ out.writeObject(elem); } } } @SuppressWarnings("unchecked") private static <T> void readExternalCollection(ObjectInput in, List<T> dest) throws IOException, ClassNotFoundException { int size = in.readInt(); for(int i = 0; i < size; i++) { dest.add((T)in.readObject()); } } @Override public String toString() { return "{"+field1+","+field2+","+field3+"}"; } }
package com.dukesoftware.demos.externalizable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.List; public class ExternalizableClass implements Externalizable{ private String field1; private Double field2; private List<String> field3; public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public Double getField2() { return field2; } public void setField2(Double field2) { this.field2 = field2; } public List<String> getField3() { return field3; } public void setField3(List<String> field3) { this.field3 = field3; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(field1); out.writeDouble(field2); writeExternalCollection(out, field3); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { field1 = (String)in.readObject(); field2 = in.readDouble(); field3 = new ArrayList<>(); readExternalCollection(in, field3); } private static <T> void writeExternalCollection(ObjectOutput out, List<T> c) throws IOException { if(c == null) { out.writeInt(-1); } else { out.writeInt(c.size()); for(T elem : c){ out.writeObject(elem); } } } @SuppressWarnings("unchecked") private static <T> void readExternalCollection(ObjectInput in, List<T> dest) throws IOException, ClassNotFoundException { int size = in.readInt(); for(int i = 0; i < size; i++) { dest.add((T)in.readObject()); } } @Override public String toString() { return "{"+field1+","+field2+","+field3+"}"; } }
Performance Comparison - Default Serialization vs Custom Externalizable
I wrote simple testing code for measuring performance of serialization.The result, which is tested on my local windows machine, is below. Measuring the time for 1000000 iteration of serialization
Externalization : 6591 msec
Default Serialization: 13864 msec
Wow! using Externalizable is almost twice faster than default serialization implmentation.
Default Serialization: 13864 msec
Just for your reference, my testing enviroment is below
OS | Windows 7 64bit |
Java | JDK 1.7.0u40 |
Memory | 16GB |
CPU | Phenom II 910e |
Note | Just quick run on eclipse with no jvm optional arguments. |
package com.dukesoftware.demos.externalizable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.Arrays; import java.util.TreeMap; public class ExternalizableTest { private static final int ITERATION = 1000000; public static void main(String[] args) throws IOException, ClassNotFoundException { // 1) Custom Serialization using Externalizable ExternalizableClass obj1 = new ExternalizableClass(); obj1.setField1("value1"); obj1.setField2(2d); obj1.setField3(Arrays.asList("A", "B", "C")); ExternalizableTreeMap<String, ExternalizableClass> map1 = new ExternalizableTreeMap<>(); map1.put("key1", obj1); // 2) Default Serializable SerializableClass obj2 = new SerializableClass(); obj2.setField1("value1"); obj2.setField2(2d); obj2.setField3(Arrays.asList("A", "B", "C")); TreeMap<String, SerializableClass> map2 = new TreeMap<>(); map2.put("key1", obj2); System.out.println("-- Serialized and check total bytes --"); byte[] serializedBytes1 = toSerializedBytes(map1); System.out.println("Externalizable Result : "+ serializedBytes1.length); byte[] serializedBytes2 = toSerializedBytes(map2); System.out.println("Default Serializable Result: " + serializedBytes2.length); // just confirm the serialized bytes can be deserialized to object properly // if you really want to confirm the original object and the object loaded back from serialized bytes are same, // you should implement appropriate equlas method System.out.println("\n-- Check deserialized value --"); ExternalizableTreeMap<String, ExternalizableClass> map1read = readSerializedBytes(serializedBytes1); System.out.println(map1read); TreeMap<String, SerializableClass> map2read = readSerializedBytes(serializedBytes2); System.out.println(map2read); // Performance comparison! System.out.println("\n-- Compare performance --"); executeSerializationRepeatedly(map1, ITERATION); executeSerializationRepeatedly(map2, ITERATION); } private static void executeSerializationRepeatedly(Object obj, int iteration) throws IOException { long start = System.currentTimeMillis(); for(int i = 0; i < iteration; i++) { toSerializedBytes(obj); } System.out.println(System.currentTimeMillis() - start + " msec/"+ITERATION+"iteration"); } private static byte[] toSerializedBytes(Object obj) throws IOException { // you can use FileOutputStream instead of ByteArrayOutputStream // if you would like to write serialized bytes to file ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutput output = new ObjectOutputStream(baos); output.writeObject(obj); // you can use toString method if you would like to see the serialized content as string return baos.toByteArray(); } @SuppressWarnings("unchecked") private static <T> T readSerializedBytes(byte[] bytes) throws IOException, ClassNotFoundException { InputStream buffer = new ByteArrayInputStream(bytes); ObjectInput input = new ObjectInputStream (buffer); return (T) input.readObject(); } }
package com.dukesoftware.demos.externalizable; import java.io.Serializable; import java.util.List; public class SerializableClass implements Serializable{ private String field1; private Double field2; private List<String> field3; public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public Double getField2() { return field2; } public void setField2(Double field2) { this.field2 = field2; } public List<String> getField3() { return field3; } public void setField3(List<String> field3) { this.field3 = field3; } @Override public String toString() { return "{"+field1+","+field2+","+field3+"}"; } }
コメント