Cómo serializar una lambda?
¿Cómo puedo serializar elegantemente una lambda?
Por ejemplo, el siguiente código arroja un NotSerializableException
. ¿Cómo puedo arreglarlo sin crear una interfaz SerializableRunnable
"ficticia"?
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();
}
}
4 answers
Java 8 introduce la posibilidad de enviar un objeto a una intersección de tipos agregando múltiples límites. En el caso de serialización, por lo tanto, es posible escribir:
Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
Y la lambda automáticamente se vuelve serializable.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-02 10:09:49
Se puede usar la misma construcción 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 destino serializable.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-25 01:01:01
Reparto muy feo. Prefiero definir una extensión serializable a 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 se puede definir como tal:
private void someFunction(SerializableFunction<String, Object> function) {
...
}
Y llamando a la función puede pasar su lambda sin ningún feo molde:
someFunction(arg -> doXYZ(arg));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 18:27:54
Si está dispuesto a cambiar a otro framework de serialización como Kryo, puede deshacerse de los múltiples límites o del requisito de que la interfaz implementada debe implementar Serializable
. El enfoque es
- Modifica el
InnerClassLambdaMetafactory
para generar siempre el código necesario para la serialización - Llame directamente al
LambdaMetaFactory
durante la deserialización
Para los detalles y el código ver este entrada de blog
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-07 11:59:34