Java 如何序列化lambda?

Java 如何序列化lambda?,java,serialization,lambda,java-8,Java,Serialization,Lambda,Java 8,如何优雅地序列化lambda 例如,下面的代码抛出一个NotSerializableException。如何在不创建SerializableRunnable虚拟接口的情况下修复它 public static void main(String[] args) throws Exception { File file = Files.createTempFile("lambda", "ser").toFile(); try (ObjectOutput oo = new ObjectO

如何优雅地序列化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();
    }
}

Java8引入了实现的可能性。因此,在序列化的情况下,可以写入:

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");

并且lambda自动成为可序列化的。

相同的结构可用于方法引用。例如,此代码:

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);
    }
}

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

如果您愿意切换到其他类似的序列化框架,则可以消除多个边界或实现的接口必须实现可序列化的要求。方法是

  • 修改
    InnerClassLambdaMetafactory
    以始终生成序列化所需的代码
  • 反序列化过程中直接调用
    LambdaMetaFactory

  • 有关详细信息和代码,请参见此

    非常难看的演员阵容。我更喜欢为我正在使用的函数接口定义一个可序列化的扩展

    例如:

    interface SerializableFunction<T,R> extends Function<T,R>, Serializable {}
    interface SerializableConsumer<T> extends Consumer<T>, Serializable {}
    

    如果有人在创建梁/数据流代码时摔倒在这里:


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

    非常有趣-此功能似乎非常强大。在铸造lambdas之外,有没有使用这种铸造表达式?例如,现在是否也可以对普通匿名类执行类似操作?@Balder添加了强制转换到交叉点类型的功能,以便为lambdas的类型推断提供目标类型。因为AIC有一个清单类型(即,它的类型不是推断的),所以将AIC转换为交集类型是没有用的。(这是可能的,只是没有用。)要让AIC实现多个接口,您必须创建一个扩展所有接口的新子接口,然后对其进行实例化。这会不会产生一个编译器警告,说没有定义serialVersionUID?注意:只有在构造期间应用转换时,这才有效。下面将抛出一个ClassCastException:Runnable r=()->System.out.println(“Serializable!”);Runnable-serializableR=(Runnable&Serializable)r@B正文是也请参见:虽然这是可能的(请参见所选答案),但每个人都应该三思而后行。我喜欢这个答案,因为这样的话,任何你没有写的外部调用程序都可以自动序列化。若您希望提交的对象是可序列化的,那个么您的接口应该是可序列化的,这是接口的一个要点。然而,问题是“没有创建
    SerializableRunnable
    'dummy'接口”,帖子被移到了这里:
    private void someFunction(SerializableFunction<String, Object> function) {
       ...
    }
    
    someFunction(arg -> doXYZ(arg));