如何序列化lambda?

ass*_*ias 152 java lambda serialization java-8

我怎样才能优雅地序列化lambda?

例如,下面的代码抛出一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

ass*_*ias 250

Java 8引入了通过添加多个边界将对象强制转换为类型的交集的可能性.在序列化的情况下,因此可以写:

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
Run Code Online (Sandbox Code Playgroud)

lambda自动变为可序列化.

  • 注意:这仅适用于在施工期间应用浇筑.以下将抛出ClassCastException:Runnable r =() - > System.out.println("Serializable!"); Runnable serializableR =(Runnable&Serializable)r; (8认同)
  • @Balder添加了转换为交集类型的工具,以便为lambdas的类型推断提供目标类型.由于AIC具有清单类型(即,不推断其类型),因此将AIC转换为交集类型是没有用的.(有可能,只是没用.)要让AIC实现多个接口,您必须创建一个扩展所有接口的新子接口,然后实例化它. (6认同)
  • 非常有趣 - 这个功能似乎非常强大.在施放lambda之外是否有任何使用这种演员表达?例如,它现在也可以用普通的匿名类做类似的事情吗? (4认同)
  • @bcody是的,请参阅:http://stackoverflow.com/questions/25391656/serialization-of-a-lambda-after-its-creation (3认同)
  • 这会产生编译器警告,说没有定义serialVersionUID吗? (2认同)
  • @cypressious没有编译器警告. (2认同)

Vic*_*ero 23

相同的结构可用于方法参考.例如这段代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

定义lambda表达式和具有可序列化目标类型的方法引用.


小智 17

非常丑陋的演员.我更喜欢为我正在使用的功能接口定义Serializable扩展

例如:

interface SerializableFunction<T,R> extends Function<T,R>, Serializable {}
interface SerializableConsumer<T> extends Consumer<T>, Serializable {}
Run Code Online (Sandbox Code Playgroud)

那么接受lambda的方法可以这样定义:

private void someFunction(SerializableFunction<String, Object> function) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

并调用函数,您可以传递您的lambda没有任何丑陋的演员:

someFunction(arg -> doXYZ(arg));
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案,因为这样,您不编写的任何外部调用程序也将自动可序列化。如果要使提交的对象可序列化,则您的接口应该可序列化,这是接口的重点。但是,问题的确是“没有创建`SerializableRunnable`'虚拟'接口” (2认同)

Raf*_*aël 5

万一有人在创建 Beam/Dataflow 代码时跌倒在这里:

Beam 有自己的SerializableFunction接口,因此不需要虚拟接口或冗长的强制转换。