Java8:Lambda序列化?
本文由 ImportNew - 黄飞飞 翻译自 dzone。如需转载本文,请先参见文章末尾处的转载要求。
ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加入我们的 Java开发 小组。参与方式请查看小组简介。
最近我一直在考虑为Tyrus项目做一个优化处理,允许用户跨越集群向连接到一个URL的一部分客户端进行广播。 有很多方法可以达成目标。但自从使用了 JDK 8 后,这个问题简已经变成了我的眼中钉。
为了达到这个目的,我创建了一个简单的单元测试。通过过滤器将它序列化到磁盘上、读取然后执行。我们可以直接或间接地引用它的一个实例字段 “VALUE”,以此来查出究竟是什么导致了序列化失败。
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.function.Predicate; import org.junit.Test; public class SerializablePredicateFilterTest { public String VALUE = "Bob"; public interface SerializablePredicate<T> extends Predicate<T>, Serializable {} public <T> void filter(SerializablePredicate<T> sp, T value) throws IOException, ClassNotFoundException { sp.getClass().isLocalClass(); File tempFile = File.createTempFile("labmda", "set"); try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(tempFile))) { oo.writeObject(sp); } try (ObjectInput oi = new ObjectInputStream(new FileInputStream(tempFile))) { SerializablePredicate<T> p = (SerializablePredicate<T>) oi.readObject(); System.out.println(p.test(value)); } } }
既然只是为了校对,我们可以让匿名内部类测试失败,因为它总是包含了一个宿主类的对象的引用……
@Test(expected = NotSerializableException.class) public void testAnonymousDirect() throwsIOException, ClassNotFoundException { String value = VALUE; filter(newSerializablePredicate<String>() { @Override public boolean test(String t) { return value.length() > t.length(); } }, "Bob"); }
对于本地类来说同样如此, 本地类有什么不可以使用呢?
@Test(expected = NotSerializableException.class) public void testLocalClass() throws IOException, ClassNotFoundException { class LocalPredicate implements SerializablePredicate<String> { @Override public boolean test(String t) { // TODO Implement this method return false; } } filter(new LocalPredicate(), "Bobby"); }
一个独立的类当然可以工作,在这个示例中为了方便起见使用了一个嵌套类。
public static class LengthPredicate implements SerializablePredicate<String> { private String value; public LengthPredicate(String value) { super(); this.value = value; } public void setValue(String value) { this.value = value; } public String getValue() { return value; } @Override public boolean test(String t) { // TODO Implement this method return false; } } @Test public void testStaticInnerClass() throws IOException, ClassNotFoundException { filter(new LengthPredicate(VALUE), "Bobby"); }
我们还是使用JDK 8,结果证明我的第一个try也失败了。但它证明了,通常情况下序列化是非常乐意接受一个Lambda表达式的。
@Test(expected = NotSerializableException.class) public void testLambdaDirect() throws IOException, ClassNotFoundException { filter((String s) -> VALUE.length() > s.length(), "Bobby"); }
稍微做下改动,拷贝值到一个有效的final属性中。瞧,lambda现在被正确地序列化并且恢复了。
@Test public void testLambdaInDirect() throws IOException, ClassNotFoundException { String value = VALUE; filter((String s) -> value.length() > s.length(), "Bobby"); }
当然,如果value是一个简单方法的参数,也可以工作正常。
@Test public void testLambdaParameter() throws IOException, ClassNotFoundException { invokeWithParameter(VALUE); } private void invokeWithParameter(String value) throws java.lang.ClassNotFoundException, java.io.IOException { filter((String s) -> value.length() > s.length(), "Bobby"); }
因此答案是肯定的,只要你小心一点就可以对lambda进行序列化。
原文链接: dzone 翻译: ImportNew.com - 黄飞飞
译文链接: http://www.importnew.com/8554.html
[ 转载请保留原文出处、译者和译文链接。]