无法反序列化lambda
就像一个小项目一样,我一直试图做一个小东西,读取序列化的lambdas(本地或从FTP)并调用它们的运行函数作为测试的一部分来试验Windows中的文件关联(即打开某些文件类型)用某个程序打开它们等等,但无论我尝试什么,它似乎都没有正确地反序列化。
lambda被宣布为这样
Runnable r = (Runnable & Serializable) () -> { // blah blah // made sure not to capture anything };
并使用由ObjectOutputStream包装的[n optional] BufferedOutputStream包装的FileOutputStream进行序列化,没有问题。 但是,当[在不同的项目中]反序列化时,它会失败,说它无法找到包含序列化代码的封闭类。 我已经尝试了各种各样的东西,比如将它们包装在一个可序列化的类中(用于测试目的的w / serialVersionUID = 0L)或定义一个扩展Runnable和Serializable的接口,但无济于事。
是的,我知道序列化lambda不是很好的做法(或者我们被告知),但我不知道如何将函数和子程序转换成我可以存储为文件或FTP的东西。 如果这根本不是正确的方法,请告诉我们。
哦,我正在使用最新版本的Eclipse Luna。
编辑:
像这样反序列化
File f = new File(somePath); FileInputStream fish = new FileInputStream(f); BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary ObjectInputStream ois = new ObjectInputStream(bos); Runnable r = (Runnable) ois.readObject(); ois.close(); r.run();
如果没有定义它的类,则无法反序列化对象。 这与lambda表达式没有改变。
Lambda表达式有点复杂,因为它们生成的运行时类不是定义它的类,但是它们的定义类是保存lambda体的代码的类,并且在可序列化的lambdas的情况下,是用于validation的反序列化支持方法。并重新实例化lambda实例。
请参见SerializedLambda
:
可序列化lambda的实现者,例如编译器或语言运行库,应该确保实例正确地反序列化。 这样做的一种方法是确保
writeReplace
方法返回SerializedLambda
的实例,而不是允许默认序列化继续进行。
SerializedLambda
有一个readResolve
方法,它在捕获类中查找名为$deserializeLambda$(SerializedLambda)
的(可能是私有的)静态方法,并将其自身作为第一个参数调用,并返回结果。 实现$deserializeLambda$
Lambda类负责validationSerializedLambda
的属性是否与该类实际捕获的lambda一致。
因此,即使您的实例未在定义类中引用合成方法(例如,在对此类之外的方法的方法引用的情况下),反序列化仍然需要$deserializeLambda$
来有意地validation实例的正确性。
关于序列化lambda的“良好实践”,请记住lambda表达式封装了行为 ,而不是状态。 存储行为总是意味着只存储某种引用并需要用于恢复它的代码,以实现相关的行为。 如果您只是通过符号名称引用预期行为或仅存储(例如关联的enum
值),那么这也会起作用。
有关可序列化lambda的含义的更多信息将在此问题中进行解释。
反序列化对象时,执行反序列化的代码必须知道序列化对象的类。 您不能序列化任意lambda并在另一个代码库中反序列化它。
或多或少,序列化和反序列化代码必须位于相同的代码库中,或者至少必须共享对包含原始lambda的代码的依赖性。