Вопрос-ответ

How to serialize a 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();
}
}
Переведено автоматически
Ответ 1

Java 8 предоставляет возможность приводить объект к пересечению типов путем добавления нескольких границ. Следовательно, в случае сериализации можно написать:

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

И лямбда автоматически становится сериализуемой.

Ответ 2

Очень уродливое приведение. Я предпочитаю определять сериализуемое расширение для функционального интерфейса, который я использую

Например:

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));
Ответ 3

Та же конструкция может использоваться для ссылок на методы. Например, этот код:

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

определяет лямбда-выражение и ссылку на метод с сериализуемым целевым типом.

Ответ 4

На случай, если кто-то попадет сюда при создании кода Beam / Dataflow :

Beam имеет свой собственный интерфейс SerializableFunction, поэтому нет необходимости в фиктивном интерфейсе или подробных приведениях.

java serialization lambda java-8