람다를 우아하게 직렬화하는 방법은 무엇입니까?
예를 들어, 아래 코드는를 던집니다 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가 있으므로 더미 인터페이스 나 자세한 캐스트가 필요하지 않습니다.