Java中Lambda表达式的序列化
在这里,我们将讨论Java的序列化以及与没有序列化的 lambda函数相关的问题,同时讨论一些方法,因为我们需要在正确实现的同时进行序列化,就像在使用函数接口的具有完整序列化和反序列化过程的干净Java程序中一样。
序列化是将对象的状态写入字节流以便我们可以通过网络传输它的过程。我们可以序列化一个 lambda 表达式,如果它的目标类型和它捕获的参数已经序列化了。但是,与内部类一样,强烈不鼓励 lambda 表达式的序列化。由于默认情况下 lambda函数未序列化,我们只需将 lambda 转换为Java.io.Serializable。但是提交方法需要一个 Runnable 或 Callable 作为参数,而不是一个 Serializable。所以,我们必须同时将 lambda 转换为两个接口 Runnable 和 Serializable。 Java Serialization 是一个很好的通用的、向后兼容的序列化库。替代方案试图解决的两个最常见的问题是性能和跨平台序列化。相比之下,一个简单的二进制 YAML 序列化使用 348,有更多选项来优化序列化。这引发了如何使用替代、跨平台或更快的序列化格式序列化 lambda 的问题。
Note: There occurs a necessity to serialize a lambda function because Serializing lambdas can be useful in a number of use cases such as persisting configuration, or as a visitor pattern to remote resources.
Illustration: Remote visitor
Say We want to access a resource on a remote Map. We can use get/put, but say we just want to return a field from the value of a Map: we can pass a lambda as a visitor to extract the information we want. As you can see, it is easy to add various simple functions, or call a method to perform the action you need. The only problem is that lambdas by default are not serializable.
例子
MapView userMap = Chassis.acquireMap("users", String.class, UserInfo.class);
userMap.put("userid", new UserInfo("User's Name"));
// Print out changes
userInfo.registerSubscriber(System.out::println);
// Obtain just the fullName without downloading the whole object
String name= userMap.applyToKey("userid", u -> u.fullName);
// Increment a counter atomically and trigger
// an updated event printed with the subscriber.
userMap.asyncUpdateKey("userid", ui -> {
ui.usageCounter++;
return ui;
});
// Incrementimng counter and return the userid
int count = userMap.syncUpdateKey("userid",
ui -> { ui.usageCounter++; return ui;},
ui -> ui.usageCounter);
SerializedLambda类被编译器和库用来确保 lambda 正确反序列化。使函数
添加这种额外的 & Serializable 转换是一种允许 Kryo 反序列化 lambda 的可能解决方案。另一种方法是创建一个新接口,该接口既扩展了您需要的底层函数类型,又扩展了 Serializable。
布局:
public class IntersectionCasting {
public static void main(String[] args) {
SerializableLambda function = (message) -> "Kryo please serialize this message '" + message + "'";
}
interface SerializableLambda extends Function, Serializable {}
}
现在,为了在我们的 API 中使 Lambdas Serializable 保持最重要的安全,遗憾的是标准 API 无法更改或子类无法添加此功能,但如果您有自己的 API,则可以使用 Serializable 接口。 API 的用户不必明确说明 lambda 是可序列化的。远程实现序列化 lambda,在服务器上执行它,并返回结果。类似地,有一些方法可以将 lambda 应用于整个地图。
例子:
Java
// Java Program to serialize and deserialize the lambda
// function using a function interface
// Importing input output classes
import java.io.*;
// Importing all function utility classes
import java.util.function.*;
// Interaface
interface MyInterface {
// Method inside this interface
void hello(String name);
}
// Class 1
// Helper class implementing above interface
class MyImpl implements MyInterface {
// Method of this class
public void hello(String name)
{
System.out.println("Hello " + name);
}
}
// Class 2
// Main class
class GFG {
// Method 1
// To Serialize
private static void serialize(Serializable obj,
String outputPath)
throws IOException
{
File outputFile = new File(outputPath);
if (!outputFile.exists()) {
outputFile.createNewFile();
}
try (ObjectOutputStream outputStream
= new ObjectOutputStream(
new FileOutputStream(outputFile))) {
outputStream.writeObject(obj);
}
}
// Method 2
// To Deserialize
private static Object deserialize(String inputPath)
throws IOException, ClassNotFoundException
{
File inputFile = new File(inputPath);
try (ObjectInputStream inputStream
= new ObjectInputStream(
new FileInputStream(inputFile))) {
return inputStream.readObject();
}
}
// Method 3
// To Serialize and deserialize lambda functions
private static void serializeAndDeserializeFunction()
throws Exception
{
Function fn
= (Function & Serializable)(n)
-> "Hello " + n;
System.out.println("Run original function: "
+ fn.apply(10));
String path = "./serialized-fn";
serialize((Serializable)fn, path);
System.out.println("Serialized function to "
+ path);
Function deserializedFn
= (Function)deserialize(path);
System.out.println("Deserialized function from "
+ path);
System.out.println("Run deserialized function: "
+ deserializedFn.apply(11));
}
// Method 4
// To Serialize and deserialize lambda classes
private static void serializeAndDeserializeClass()
throws Exception
{
String path = "./serialized-class";
serialize(MyImpl.class, path);
System.out.println("Serialized class to " + path);
// Pretending we don't know the exact class of the
// serialized bits, create an instance from the
// class and use it through the interface.
Class> myImplClass = (Class>)deserialize(path);
System.out.println("Deserialized class from "
+ path);
MyInterface instance
= (MyInterface)myImplClass.newInstance();
instance.hello("Java");
}
// Method 5
// Main driver method
public static void main(String[] args) throws Exception
{
// Calling above method 3 and method 4
// in the main() body
serializeAndDeserializeFunction();
serializeAndDeserializeClass();
}
}
输出:
Run original function: Hello 10
Serialized function to ./serialized-fn
Deserialized function from ./serialized-fn
Run deserialized function: Hello 11
Serialized class to ./serialized-class
Deserialized class from ./serialized-class
Hello Java