无法反序列化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的代码的依赖性。