0%

lambda可序列化

Lambda 可序列化

在想要动态获取lambda运行时候的属性就必须使用可序列化的labmda表达式,就要借助序列化操作将运行时的运行方法给获取出来。

就比如说,有下面这一段代码:

1
2
3
4
5
6
7

@Test
public void resolve() {
LambdaObj lambdaObj = new LambdaObj();
LambdaObj2 lambdaObj2 = new LambdaObj2();
FiledUtils.copyProperties(lambdaObj, lambdaObj2, LambdaObj::getName, LambdaObj::getSex);
}

我在代码运行的时候传递了LambdaObj的getName和getSex两个lambda表达式进行,但是我并不需要执行getName的方法而是需要获取name的这个字段,就像:

1
FiledUtils.copyProperties(lambdaObj, lambdaObj2, "name","sex")

只是借助了lambda达到不用手动写死字符串的操作。

通过序列化的方式能够实现这个操作,JDK中提供了SerializedLambda类来表达lambdda的序列化形式,这个类存储了lambda表达式存储的信息,比如接口方法的标识、实现方法的元素等。

在编译器编译时,如果lambda接口实现了序列化接口,则会自动生成一个writeReplace方法返回一个SerializedLambda实例。

1
2
3
4
5
6
7
8
9
10
11
12
private static SerializedLambda resolve(SFunction lambda) {
SerializedLambda sl = null;
try {
Method writeReplace = lambda.getClass()
.getDeclaredMethod("writeReplace");
writeReplace.setAccessible(true);
sl = (SerializedLambda) writeReplace.invoke(lambda);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return sl;
}

在运行时debug发现能看见implMethodName就是我们在使用lambda表达式的时候传入的方法。

lambda接口必须实现序列化标示,我发现JDK自带的接口并没有支持可序列化的。因此需要自己去继承并实现一下。我选择直接继承Function的

1
2
3
4
5
6
7
8
9
10
public interface SFunction<T, R> extends Function<T, R>, Serializable {


}

public static <T, O> Optional<O> copyProperties(T source,
O target,
SFunction<T, ?>... cl) {
return copyProperties(source, target, null, null, false, columnsToString(cl));
}