最近我一直在考慮爲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