Java 1.8之后,新增了一个叫做SerializedLambda
的类,它用来保存Lambda表达式序列化之后的数据,通过SerializedLambda
可以获取Lambda表达式的各种元信息,包括参数类型、返回值类型等。
下面的代码可以获取一个Lambda表达式对应的SerializedLambda
实例:
interface Function2<R, T1, T2> extends Serializable {
R apply(T1 t1, T2 t2);
}
try {
Function2<String, Integer, Double> lambda = (a, b) -> a + "," + b;
Method method = lambda.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(true);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(lambda);
System.out.println(serializedLambda);
} catch (Exception e) {
throw new RuntimeException("获取Lambda信息失败", e);
}
以上代码能工作的前提是,用于接收Lambda表达式的函数式接口必须继承自Serializable
,就像Function2
接口一样。
SerializedLambda
中的内容十分丰富,包含以下属性:
public final class SerializedLambda implements Serializable {
/**
* The capturing class.
*/
private final Class<?> capturingClass;
/**
* The functional interface class.
*/
private final String functionalInterfaceClass;
/**
* The functional interface method name.
*/
private final String functionalInterfaceMethodName;
/**
* The functional interface method signature.
*/
private final String functionalInterfaceMethodSignature;
/**
* The implementation class.
*/
private final String implClass;
/**
* The implementation method name.
*/
private final String implMethodName;
/**
* The implementation method signature.
*/
private final String implMethodSignature;
/**
* The implementation method kind.
*/
private final int implMethodKind;
/**
* The instantiated method type.
*/
private final String instantiatedMethodType;
/**
* The captured arguments.
*/
private final Object[] capturedArgs;
}
完整说明可参见JDK源码的注释。
要获取Lambda表达式对应的参数类型和返回值类型,可使用其中的instantiatedMethodType
属性,它的一般形式如下:
(Ljava/lang/Integer;Ljava/lang/Double;)Ljava/lang/String;
其中,括号里面的是参数类型,括号外面的是返回值类型,每个类型都以L
开头,以分号结尾。以上字符串表明当前Lambda函数的参数类型是[java.lang.Integer, java.lang.Double]
,返回值类型是java.lang.String
。很容易使用正则表达式解析出对应的信息。
为方便SerializedLambda
的使用,可以将相关方法封装成一个公共接口:
public interface SerializableLambda extends Serializable {
Pattern RETURN_TYPE_PATTERN = Pattern.compile("\\(.*\\)L(.*);");
Pattern PARAMETER_TYPE_PATTERN = Pattern.compile("\\((.*)\\).*");
default SerializedLambda getSerializedLambda() {
try {
Method method = getClass().getDeclaredMethod("writeReplace");
method.setAccessible(true);
return (SerializedLambda) method.invoke(this);
} catch (Exception e) {
throw new RuntimeException("获取Lambda信息失败", e);
}
}
/**
* 获取Lambda表达式返回类型
*/
default Class<?> getReturnType() {
String expr = getSerializedLambda().getInstantiatedMethodType();
Matcher matcher = RETURN_TYPE_PATTERN.matcher(expr);
if (!matcher.find() || matcher.groupCount() != 1) {
throw new RuntimeException("获取Lambda信息失败");
}
String className = matcher.group(1).replace("/", ".");
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("无法加载类", e);
}
}
/**
* 获取Lambda表达式的参数类型
*/
default List<Class<?>> getParameterTypes() {
String expr = getSerializedLambda().getInstantiatedMethodType();
Matcher matcher = PARAMETER_TYPE_PATTERN.matcher(expr);
if (!matcher.find() || matcher.groupCount() != 1) {
throw new RuntimeException("获取Lambda信息失败");
}
expr = matcher.group(1);
return Arrays.stream(expr.split(";"))
.filter(s -> !s.isBlank())
.map(s -> s.replace("L", "").replace("/", "."))
.map(s -> {
try {
return Class.forName(s);
} catch (ClassNotFoundException e) {
throw new RuntimeException("无法加载类", e);
}
})
.collect(Collectors.toList());
}
}
只需让接收Lambda表达式的函数式接口继承自SerializableLambda
,就可以方便地获取Lambda表达式的参数类型和返回值类型,且可适用于任意形式的Lambda表达式,包括箭头函数的形式和方法引用的形式。
测试代码如下:
interface Function2<R, T1, T2> extends SerializableLambda {
R apply(T1 t1, T2 t2);
}
class A {
public A(Integer num, String str) {
}
}
public class Main {
public static void main(String[] args) {
testSerializableLambda((Integer a, Double b) -> a + ',' + b);
testSerializableLambda(Main::div);
testSerializableLambda(A::new);
}
private static <R, T1, T2> void testSerializableLambda(Function2<R, T1, T2> lambda) {
System.out.println("参数类型:" + lambda.getParameterTypes());
System.out.println("返回值类型:" + lambda.getReturnType());
}
private static double div(int a, int b) {
return a * 1.0 / b;
}
}
输出结果:
参数类型:[class java.lang.Integer, class java.lang.Double]
返回值类型:class java.lang.Double
参数类型:[class java.lang.Integer, class java.lang.Integer]
返回值类型:class java.lang.Double
参数类型:[class java.lang.Integer, class java.lang.String]
返回值类型:class byx.test.A