首页 > 解决方案 > 如何保持 lambda 的参数类型?

问题描述

这是一个奇怪的 Java 反射问题,由于类型擦除而发生:

<P, R> void printIt(Function<P, R> function) {
        inner(function);
    }

    private void inner(Object function) {
        for (Method method : function.getClass().getDeclaredMethods()) {
            System.out.println(method);
        }
    }

    @Test
    public void testAnyHandler() {
        printIt((String a) -> "Hello");
    }

结果是:

public java.lang.Object com.dariodario.sqlsmile.QueryTest$$Lambda$1/1607460018.apply(java.lang.Object)

真是太可惜了……有什么办法可以保留参数吗?

标签: javareflectiontype-erasure

解决方案


并非如此,编译器不会保留此数据。您可以为 lambda 创建一个单独的类:

interface StringFunc extends Function<String, String> {}

然后就可以通过 StringFunc 超级接口来获取Function<String, String>.

或者只使用类而不是 lambda:

    printIt(new Function<String, String>() {
        @Override
        public String apply(String s) {
            return s;
        }
    });

Lambda 还在声明它们的类中生成合成方法:

    Function<String, String> x = (String a) -> a;
    printIt(x);

    for (Method declaredMethod : Test.class.getDeclaredMethods()) {
        if (declaredMethod.isSynthetic()) {
            System.out.println(declaredMethod);
        }
    }
}

将打印

public java.lang.Object org.gotofinal.Test$$Lambda$14/0x0000000800066840.apply(java.lang.Object)
private static java.lang.String org.gotofinal.Test.lambda$main$0(java.lang.String)

但是我看不到获取 lambda 声明类的选项(但可以从类名中提取)以及如何将方法与 lambda 匹配 + 它是特定于实现的,因此可能不适用于每个 jvm 版本。此方法还将包括传递给 lambda 的局部变量类型:

    int dd = "dddd".length() + args.length;
    Function<String, String> x = (String a) -> a + dd;

将打印:

private static java.lang.String org.gotofinal.Test.lambda$main$0(int,java.lang.String)

所以可能你最好的选择是将类型作为单独的参数传递:

public <F, T> Whatever method(Class<F> typeF, Class<T> typeT, Function<F, T> func)

推荐阅读