Получить подробную информацию о лямбда
Сказать, что?
В Java8 добавлены лямбда-выражения, чаще всего они используются для сотрудничестваStream
Делайте операции по сбору. Вот вещь, похожая на пасхальное яйцо, которую можно чудесно использовать для определенных случаев.
Общее использование, например следующее
Optional.of(1L).ifPresent(number -> {
System.out.println(number);
});
или упрощенно до этого
Optional.of(1L).ifPresent(System.out::println);
Есть ли способ получитьSystem.out::println
Строка имени метода внутриString methodName = "println"
?
Какой эффект?
выполнить код
FnConverter<Foo> fnConverter = new FnConverter<>();
String fieldName = fnConverter.convertFnToString(Foo::getBar);
System.out.println("方法名:"+fieldName);
выход
方法名:bar
Как это сделать?
Шаг 1: ОпределитеFunctionalInterface
(Постучать по доске, нарисовать ключевые моментыextends Serializable
)
/**
* @author Frank
*/
@FunctionalInterface
public interface Fn<T> extends Serializable {
Object apply(T source);
}
Второе полотно: приготовить класс (соевый соус)
import lombok.Data;
/**
* @author liuyuyu
*/
@Data
public class Foo {
private Integer bar;
}
Шаг 3: ПолучитеFn
информационные инструменты
import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
/**
* @author Frank
*/
public class Reflections {
private Reflections() {
}
public static String fnToFieldName(Fn fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
String getter = serializedLambda.getImplMethodName();
String fieldName = Introspector.decapitalize(getter.replace("get", ""));
return fieldName;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
привлечь вниманиеSerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
Шаг 4: Напишите грушу и бегите
/**
* @author liuyuyu
*/
public class FnConverter<T> {
public String convertFnToString(Fn<T> fn){
return Reflections.fnToFieldName(fn);
}
public static void main(String[] args) {
FnConverter<Foo> fnConverter = new FnConverter<>();
String fieldName = fnConverter.convertFnToString(Foo::getBar);
System.out.println("方法名:"+fieldName);
}
}
Run
方法名:bar
Каков принцип?
Serializable
Это интерфейс для сериализации объектов Java. Любой, кто реализует этот интерфейс (интерфейс является наследованием, также считается), Java должен предоставить методы сериализации и десериализации (ObjectInputStream/ObjectOutputStream
может что-то напомнить).
Но лямбда особенная, это метод, ее можно рассматривать как действие (или кунг-фу? Например, Jiuyin Zhenjing), ее нельзя сохранить напрямую, Java предоставляетSerializedLambda
Этот класс содержит информацию о лямбде.
public final class SerializedLambda implements Serializable {
private static final long serialVersionUID = 8025925345765570181L;
private final Class<?> capturingClass;
private final String functionalInterfaceClass;
private final String functionalInterfaceMethodName;
private final String functionalInterfaceMethodSignature;
private final String implClass;
private final String implMethodName;
private final String implMethodSignature;
private final int implMethodKind;
private final String instantiatedMethodType;
private final Object[] capturedArgs;
//省略之后代码
}
Зная эту скрытую (цветную) особенность (яйцо), давайте вернемся к ключевым точкам, нарисованным на доске только что.
@FunctionalInterface //lambda
public interface Fn<T> extends Serializable //序列化接口
Оба условия выполняются
Поскольку эта вещь является скрытой (цветной) функцией (яйцо), мы не можем получить ее напрямую.SerializedLambda
. Прямо на отражение!
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
Таким образом, мы можем получить имя метода лямбды
Что еще можно сделать?
В дизайне фреймворка во многих сценариях необходимо получить атрибуты класса.До Java 8 дизайн API мог использовать только строковый метод.Если это Java 8, строки можно избежать.
Вы можете открыть каштан (лжеца) и запустить код напрямую, чтобы почувствовать его.