¿Cómo serializar una lambda?

¿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 objective serializable.

Elenco muy feo. Prefiero definir una extensión Serializable para la interfaz funcional que estoy usando

Por ejemplo:

 interface SerializableFunction extends Function, Serializable {} interface SerializableConsumer extends Consumer, Serializable {} 

entonces el método que acepta la lambda puede definirse como tal:

 private void someFunction(SerializableFunction function) { ... } 

y llamando a la función puedes pasar tu lambda sin ningún molde feo:

 someFunction(arg -> doXYZ(arg)); 

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

  1. Modifique InnerClassLambdaMetafactory para generar siempre el código requerido para la serialización
  2. Llamar directamente a la LambdaMetaFactory durante la deserialización

Para detalles y código, vea esta publicación en el blog