Java是一種可以撰寫(xiě)跨平臺(tái)應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言。Java 技術(shù)具有卓越的通用性、高效性、平臺(tái)移植性和安全性,廣泛應(yīng)用于PC、數(shù)據(jù)中心、游戲控制臺(tái)、科學(xué)超級(jí)計(jì)算機(jī)、移動(dòng)電話和互聯(lián)網(wǎng),同時(shí)擁有全球最大的開(kāi)發(fā)者專業(yè)社群。
給你學(xué)習(xí)路線:html-css-js-jq-javase-數(shù)據(jù)庫(kù)-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm

Java8新增了lambda表達(dá)式,最常見(jiàn)的用法是配合 Stream 做集合操作。下面是一種類似彩蛋的東西可以妙用到某些場(chǎng)合。
一般用法,比如下面這樣
Optional.of(1L).ifPresent(number -> { System.out.println(number);});
或者簡(jiǎn)化成這樣
Optional.of(1L).ifPresent(System.out::println);
有什么辦法能獲取到 System.out::println 里面的方法名字符串 String methodName = "println" ?
啥效果?

小編推薦一個(gè)學(xué)Java的學(xué)習(xí)裙【 七六零,二五零,五四一 】,無(wú)論你是大牛還是小白,是想轉(zhuǎn)行還是想入行都可以來(lái)了解一起進(jìn)步一起學(xué)習(xí)!裙內(nèi)有開(kāi)發(fā)工具,很多干貨和技術(shù)資料分享!
執(zhí)行代碼
FnConverter fnConverter = new FnConverter<>();String fieldName = fnConverter.convertFnToString(Foo::getBar);System.out.println("方法名:"+fieldName);
輸出
方法名:bar
怎么做?
第一步:定義一個(gè) FunctionalInterface (敲黑板,畫(huà)重點(diǎn) extends Serializable )
/** * @author Frank */@FunctionalInterfacepublic interface Fn extends Serializable { Object apply(T source);}
第二布:準(zhǔn)備個(gè)類(醬油)
import lombok.Data;/** * @author liuyuyu */@Datapublic class Foo { private Integer bar;}
第三步:獲取 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); } }}
畫(huà)重點(diǎn) SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
第四步:寫(xiě)個(gè)梨子跑起來(lái)
/** * @author liuyuyu */public class FnConverter { public String convertFnToString(Fn fn){ return Reflections.fnToFieldName(fn); } public static void main(String[] args) { FnConverter fnConverter = new FnConverter<>(); String fieldName = fnConverter.convertFnToString(Foo::getBar); System.out.println("方法名:"+fieldName); }}
Run
方法名:bar
啥原理?
Serializable 是Java對(duì)象序列化的接口,凡是實(shí)現(xiàn)這個(gè)接口(interface是繼承,也算)Java都要提供序列化和反序列化的方法( ObjectInputStream/ObjectOutputStream 可能會(huì)讓你想起點(diǎn)什么)。
但是lambda比較特殊,它是一個(gè)方法,可以認(rèn)為是一個(gè)動(dòng)作(或者說(shuō)是功夫?比如九陰真經(jīng)),沒(méi)辦法直接保存,Java提供了 SerializedLambda 這個(gè)類保存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; //省略之后代碼}

小編推薦一個(gè)學(xué)Java的學(xué)習(xí)裙【 七六零,二五零,五四一 】,無(wú)論你是大牛還是小白,是想轉(zhuǎn)行還是想入行都可以來(lái)了解一起進(jìn)步一起學(xué)習(xí)!裙內(nèi)有開(kāi)發(fā)工具,很多干貨和技術(shù)資料分享!
知道了這個(gè)隱藏(彩)特性(蛋),我們回頭看看剛才黑板上畫(huà)的重點(diǎn)
@FunctionalInterface //lambdapublic interface Fn extends Serializable //序列化接口
兩個(gè)條件滿足
因?yàn)檫@個(gè)東西是個(gè)隱藏(彩)特性(蛋),我們不能直接獲取到 SerializedLambda 。直接上反射!
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
這樣,我們就可以獲取到lambda的方法名


