如何序列化一个 lambda?
Posted
技术标签:
【中文标题】如何序列化一个 lambda?【英文标题】:How to serialize a lambda? 【发布时间】:2014-05-13 12:39:19 【问题描述】:如何优雅地序列化 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();
【问题讨论】:
虽然这是可能的(请参阅所选答案),但实际上每个人都应该三思而后行。正式名称为"strongly discouraged",可以有serioussecurityimplications。 【参考方案1】:如果你愿意切换到另一个像Kryo这样的序列化框架,你可以摆脱多重界限或者实现的接口必须实现Serializable
的要求。方法是
-
修改
InnerClassLambdaMetafactory
以始终生成序列化所需的代码
反序列化时直接调用LambdaMetaFactory
详情和代码见blog post
【讨论】:
帖子被移到这里:ruediste.github.io/java/kryo/2017/05/07/…【参考方案2】:如果有人在创建 Beam/Dataflow 代码时掉到这里:
Beam 有自己的SerializableFunction 接口,因此不需要虚拟接口或冗长的强制转换。
【讨论】:
【参考方案3】:非常丑陋的演员阵容。我更喜欢为我正在使用的功能接口定义一个 Serializable 扩展
例如:
interface SerializableFunction<T,R> extends Function<T,R>, Serializable
interface SerializableConsumer<T> extends Consumer<T>, Serializable
那么接受 lambda 的方法可以这样定义:
private void someFunction(SerializableFunction<String, Object> function)
...
并调用该函数,您可以传递您的 lambda,而无需任何丑陋的演员:
someFunction(arg -> doXYZ(arg));
【讨论】:
我喜欢这个答案,因为这样你不写的任何外部调用者也将自动被序列化。如果您希望提交的对象可序列化,则您的接口应该是可序列化的,这是接口的一种重点。但是,问题确实说“没有创建SerializableRunnable
'dummy'接口”【参考方案4】:
同样的结构可以用于方法引用。例如这段代码:
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 表达式和一个具有可序列化目标类型的方法引用。
【讨论】:
【参考方案5】:Java 8 引入了cast an object to an intersection of types by adding multiple bounds 的可能性。在序列化的情况下,因此可以这样写:
Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
并且 lambda 会自动变为可序列化。
【讨论】:
非常有趣——这个功能似乎相当强大。在转换 lambda 之外是否有使用这种转换表达式?例如。现在是否也可以用普通的匿名类做类似的事情? @Balder 添加了转换为交集类型的工具,以便为 lambda 的类型推断提供目标类型。由于 AIC 具有清单类型(即,其类型未被推断),因此将 AIC 转换为交集类型是没有用的。 (有可能,只是没用。)要让 AIC 实现多个接口,您必须创建一个扩展所有接口的新子接口,然后实例化它。 这会产生编译器警告,说没有定义serialVersionUID吗? 注意:这仅在您在施工期间应用演员表时有效。以下将抛出 ClassCastException: Runnable r = () -> System.out.println("Serializable!");可运行可序列化R = (可运行&可序列化)r; @bcody 是的,另请参阅:***.com/questions/25391656/…以上是关于如何序列化一个 lambda?的主要内容,如果未能解决你的问题,请参考以下文章
Python面试必考重点之列表,元组和字典第十二关——如果列表元素是字典序列,如何利用lambda表达式对列表进行升序降序排列
java成神之——properties,lambda表达式,序列化