Java8新增了lambda表达式,最多见的用法是配合Stream
作集合操做。下面是一种相似彩蛋的东西能够妙用到某些场合。java
通常用法,好比下面这样git
Optional.of(1L).ifPresent(number -> {
System.out.println(number);
});
复制代码
或者简化成这样github
Optional.of(1L).ifPresent(System.out::println);
复制代码
有什么办法能获取到System.out::println
里面的方法名字符串String methodName = "println"
?api
执行代码bash
FnConverter<Foo> fnConverter = new FnConverter<>();
String fieldName = fnConverter.convertFnToString(Foo::getBar);
System.out.println("方法名:"+fieldName);
复制代码
输出app
方法名:bar
框架
第一步:定义一个FunctionalInterface
(敲黑板,画重点extends Serializable
)工具
/**
* @author Frank
*/
@FunctionalInterface
public interface Fn<T> extends Serializable {
Object apply(T source);
}
复制代码
第二布:准备个类(酱油)ui
import lombok.Data;
/**
* @author liuyuyu
*/
@Data
public class Foo {
private Integer bar;
}
复制代码
第三步:获取Fn
的信息的工具类spa
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);
第四步:写个梨子跑起来
/**
* @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对象序列化的接口,凡是实现这个接口(interface是继承,也算)Java都要提供序列化和反序列化的方法(ObjectInputStream/ObjectOutputStream
可能会让你想起点什么)。
可是lambda比较特殊,它是一个方法,能够认为是一个动做(或者说是功夫?好比九阴真经),没办法直接保存,Java提供了SerializedLambda
这个类保存lambda的信息。
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);
这样,咱们就能够获取到lambda的方法名
在框架设计的时候,不少场景要获取类的属性,Java8之前API设计的时候只能用字符串方式,若是是Java8,就能够避免字符串。
你们能够打开(骗星)栗子,直接运行代码感觉一下。