Как сохранить параметры типов лямбды? - PullRequest
3 голосов
/ 05 октября 2019

Это странная проблема отражения 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)

, что действительно позор ... Есть лиМожно ли сохранить параметры?

1 Ответ

0 голосов
/ 10 октября 2019

Не совсем, эти данные не хранятся компилятором. Вы должны либо создать отдельный класс для лямбды:

interface StringFunc extends Function<String, String> {}

И затем вы можете получить суперинтерфейс StringFunc для получения Function<String, String>.

Или просто использовать классы вместо лямбда-выражений:

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

Lambdas также генерирует синтетический метод в классе, в котором они были объявлены:

    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)

Но я не вижу возможности получить класс объявлениялямбда (но может быть извлечено из имени класса) и как сопоставить метод с лямбда + это зависит от реализации, поэтому может не работать на каждой версии jvm. Также этот метод будет включать типы локальных переменных, передаваемых в лямбду:

    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)
...