[java] 람다를 직렬화하는 방법?

람다를 우아하게 직렬화하는 방법은 무엇입니까?

예를 들어, 아래 코드는를 던집니다 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);
    }
}

직렬화 가능한 대상 유형으로 람다 식과 메소드 참조를 정의합니다.


답변

아주 못생긴 캐스트. 사용중인 기능 인터페이스에 대한 직렬화 가능 확장을 정의하는 것을 선호합니다

예를 들면 다음과 같습니다.

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가 있으므로 더미 인터페이스 나 자세한 캐스트가 필요하지 않습니다.


답변

Kryo 와 같은 다른 직렬화 프레임 워크로 기꺼이 전환하려는 경우 다중 경계 또는 구현 된 인터페이스가 구현해야하는 요구 사항을 제거 할 수 있습니다 Serializable. 접근 방식은

  1. InnerClassLambdaMetafactory직렬화에 필요한 코드를 항상 생성하도록 수정
  2. LambdaMetaFactory역 직렬화 중에 직접 호출

자세한 내용과 코드는이 블로그 게시물을 참조하십시오


답변