Как сериализовать lambda?

Как я могу элегантно сериализовать 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(); } } 

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

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

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

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

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

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

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

Например:

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

то метод, принимающий lambda, может быть определен как таковой:

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

и вызывая функцию, вы можете передать свою лямбду без какого-либо уродливого броска:

 someFunction(arg -> doXYZ(arg)); 

Если вы захотите переключиться на другую схему сериализации, такую ​​как Kryo , вы можете избавиться от множественных границ или требования, которым реализованный интерфейс должен реализовывать Serializable . Подход к

  1. Измените InnerClassLambdaMetafactory чтобы всегда генерировать код, необходимый для сериализации
  2. Непосредственно вызовите LambdaMetaFactory во время десериализации

Подробности и код см. В этом блоге

  • Как десериализовать JSON с двойными именами свойств в одном и том же объекте
  • Как превратить объект C # в строку JSON в .NET?
  • Почему java.util.Optional не является Serializable, как сериализовать объект с такими полями
  • ShouldSerialize * () vs * Условный шаблон условной сериализации
  • jackson - Как обрабатывать (десериализовать) вложенный JSON?
  • Сериализация типа Json.Net с полиморфным дочерним объектом
  • Существуют ли эквиваленты C ++ для функций протокола ввода-вывода протокола Buffer в Java?
  • JSON.Net Обнаружен собственный цикл привязки
  • Как можно полиморфная десериализация Json String с использованием Java и библиотеки Jackson?
  • Как сериализовать объект в CSV-файл?
  • Использовать имя classа в качестве корневого ключа для сериализации JSON Jackson
  • Давайте будем гением компьютера.