最近我一直在考虑为Tyrus项目作一个优化处理,容许用户跨越集群向链接到一个URL的一部分客户端进行广播。 有不少方法能够达成目标。但自从使用了 JDK 8 后,这个问题简已经变成了个人眼中钉。html
为了达到这个目的,我建立了一个简单的单元测试。经过过滤器将它序列化到磁盘上、读取而后执行。咱们能够直接或间接地引用它的一个实例字段 “VALUE”,以此来查出到底是什么致使了序列化失败。java
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)); } } }
既然只是为了校对,咱们可让匿名内部类测试失败,由于它老是包含了一个宿主类的对象的引用……ide
@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如今被正确地序列化而且恢复了。this
@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进行序列化。code
原文连接: dzone 翻译: ImportNew.com - 黄飞飞
译文连接: http://www.importnew.com/8554.html
htm