我怎样才能优雅地序列化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();
}
}
Run Code Online (Sandbox Code Playgroud) 由于已经知道它很容易地添加序列化支持lambda表达式时,目标接口已经不继承Serializable
,只是喜欢(TargetInterface&Serializable)()->{/*code*/}
.
我问,是一种反其道而行之,明确删除支持串行当目标接口不继承Serializable
.
由于您无法从类型中删除接口,因此基于语言的解决方案可能看起来像(@NotSerializable TargetInterface)()->{/* code */}
.但据我所知,没有这样的解决方案.(纠正我,如果我错了,这将是一个完美的答案)
即使在类实现时拒绝序列化是Serializable
过去的合法行为,并且程序员控制下的类,模式看起来如下:
public class NotSupportingSerialization extends SerializableBaseClass {
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
throw new NotSerializableException();
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
private void readObjectNoData() throws ObjectStreamException {
throw new NotSerializableException();
}
}
Run Code Online (Sandbox Code Playgroud)
但是对于lambda表达式,程序员没有对lambda类的控制.
为什么有人会费心去除支持?好吧,除了生成包含Serialization
支持的更大代码之外,它还会产生安全风险.请考虑以下代码:
public class CreationSite {
public static void main(String... arg) {
TargetInterface f=CreationSite::privateMethod;
} …
Run Code Online (Sandbox Code Playgroud) 我知道我们可以将函数转换为Serializable
需要它的位置.
但是,我想将此转换移动到通用方法,以使使用代码更简洁.我无法创建这样的方法.
我的具体问题是下面的地图不是Serializable
:
final Map<MyObject, String> map =
new TreeMap<>(Comparator.comparing(MyObject::getCode));
Run Code Online (Sandbox Code Playgroud)
我可以通过使用:
final Map<MyObject, String> map =
new TreeMap<>(Comparator.comparing((Function<MyObject, String> & Serializable) MyObject::getCode));
Run Code Online (Sandbox Code Playgroud)
但我希望能够做到这样的事情:
final Map<MyObject, String> map =
new TreeMap<>(Comparator.comparing(makeSerializable(MyObject::getCode)));
public static <T, U> Function<T, U> makeSerializable(Function<T, U> function) {
return (Function<T, U> & Serializable) function;
}
Run Code Online (Sandbox Code Playgroud)
对于编译器这很好,但在运行时,我得到一个ClassCastException
:
java.lang.ClassCastException: SerializableTest$$Lambda$1/801197928 cannot be cast to java.io.Serializable
Run Code Online (Sandbox Code Playgroud)
我也尝试了以下替代方案,但没有成功:
// ClassCastException
public static <T extends Serializable, U extends Serializable> Function<T, U> makeSerializable(Function<T, U> …
Run Code Online (Sandbox Code Playgroud)