ラムダをエレガントにシリアル化するにはどうすればよいですか?
たとえば、次のコードはNotSerializableException
をスローします。 SerializableRunnable
"ダミー"インターフェイスを作成せずに修正するにはどうすればよいですか?
public static void main(String[] args) throws Exception {
File file = Files.createTempFile("lambda", "ser").toFile();
try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(file))) {
Runnable r = () -> System.out.println("Can I be serialized?");
oo.writeObject(r);
}
try (ObjectInput oi = new ObjectInputStream(new FileInputStream(file))) {
Runnable r = (Runnable) oi.readObject();
r.run();
}
}
Java 8では、 複数の境界を追加してオブジェクトを型の共通部分にキャストする の可能性が導入されています。したがって、シリアル化の場合、次のように記述できます。
Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
そして、ラムダは自動的にシリアライズ可能になります。
同じ構造をメソッド参照に使用できます。たとえば、次のコード:
import Java.io.Serializable;
public class Test {
static Object bar(String s) {
return "make serializable";
}
void m () {
SAM s1 = (SAM & Serializable) Test::bar;
SAM s2 = (SAM & Serializable) t -> "make serializable";
}
interface SAM {
Object action(String s);
}
}
シリアライズ可能なターゲット型を使用してラムダ式とメソッド参照を定義します。
非常にいキャスト。私は使用している機能的なインターフェースにSerializable拡張を定義することを好みます
例えば:
interface SerializableFunction<T,R> extends Function<T,R>, Serializable {}
interface SerializableConsumer<T> extends Consumer<T>, Serializable {}
次に、ラムダを受け入れるメソッドを次のように定義できます。
private void someFunction(SerializableFunction<String, Object> function) {
...
}
関数を呼び出すと、いキャストなしでラムダを渡すことができます:
someFunction(arg -> doXYZ(arg));
Beam/Dataflowコードの作成中に誰かがここに落ちた場合:
Beamには独自の SerializableFunction Interfaceがあるため、ダミーのインターフェイスや冗長なキャストは必要ありません。