java - ¿Cómo serializar una lambda?
serialization java-8 (4)
Elenco muy feo. Prefiero definir una extensión Serializable para la interfaz funcional que estoy usando
Por ejemplo:
interface SerializableFunction<T,R> extends Function<T,R>, Serializable {}
interface SerializableConsumer<T> extends Consumer<T>, Serializable {}
entonces el método que acepta la lambda puede definirse como tal:
private void someFunction(SerializableFunction<String, Object> function) {
...
}
y llamando a la función puedes pasar tu lambda sin ningún molde feo:
someFunction(arg -> doXYZ(arg));
¿Cómo puedo serializar elegantemente una lambda?
Por ejemplo, el siguiente código arroja una NotSerializableException
. ¿Cómo puedo solucionarlo sin crear una interfaz "ficticia" de 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 introduce la posibilidad de convertir un objeto en una intersección de tipos agregando múltiples límites . En el caso de la serialización, es posible escribir:
Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
Y la lambda automágicamente se vuelve serializable.
La misma construcción se puede usar para referencias de métodos. Por ejemplo, este código:
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);
}
}
define una expresión lambda y una referencia de método con un tipo de objetivo serializable.
Si está dispuesto a cambiar a otro marco de serialización como Kryo , puede deshacerse de los múltiples límites o el requisito de que la interfaz implementada debe implementar Serializable
. El enfoque es
- Modifique
InnerClassLambdaMetafactory
para generar siempre el código requerido para la serialización - Llamar directamente a la
LambdaMetaFactory
durante la deserialización
Para detalles y código, vea esta publicación en el blog