你知道Java 8 的方法引用嗎
1. 前言
Java中的方法引用,很多同學(xué)都見(jiàn)過(guò)但卻叫不出名字甚至不太會(huì)用,在這篇文章中,我們將看到什么是方法引用以及如何使用它。
2. 方法引用的使用場(chǎng)景
我們先來(lái)看看方法引用的使用:
new?Random().ints(10)
????????.map(i->Math.abs(i))
????????.forEach(i?->?System.out.println(i));
這里我們隨機(jī)生成 10 個(gè)整數(shù)然后取它們絕對(duì)值并一一打印出來(lái)。寫(xiě)法是沒(méi)有問(wèn)題的,但是還是可以再簡(jiǎn)化的。
map方法接受的是一個(gè)函數(shù)式接口IntUnaryOperator,那么上面代碼中的i->Math.abs(i)實(shí)際上是:
new?IntUnaryOperator()?{
????@Override
????public?int?applyAsInt(int?operand)?{
????????return?Math.abs(operand);
????}
}
從上面來(lái)看IntUnaryOperator就是代理了Math.abs(int i),參數(shù)列表、返回值都相同,而且沒(méi)有摻雜其它額外的邏輯。這一點(diǎn)非常重要,不摻雜其它邏輯才能相互代替。那么就可以通過(guò)方法引用來(lái)簡(jiǎn)化Lambda 表達(dá)式。上面的式子就可以簡(jiǎn)化為:
new?Random().ints(10)
????????.map(Math::abs)
????????.forEach(System.out::println);
3. 方法引用
Java 方法引用是Java 8隨著Lambda表達(dá)式引入的新特性。可以直接引用已有Java類或?qū)ο蟮姆椒ɑ驑?gòu)造器。方法引用通常與Lambda表達(dá)式結(jié)合使用以簡(jiǎn)化代碼。其使用條件是:Lambda 表達(dá)式的主體僅包含一個(gè)表達(dá)式,且 Lambda 表達(dá)式只調(diào)用了一個(gè)已經(jīng)存在的方法;被引用的方法的參數(shù)列表和返回值與 Lambda 表達(dá)式的輸入輸出一致。


3.1 格式
方法引用的格式為。也就是被引用的方法所屬的類名和方法名用雙冒號(hào)::隔開(kāi),構(gòu)造器方法是個(gè)例外,引用會(huì)用到new關(guān)鍵字,總結(jié)了一下:
| 引用方式 | 說(shuō)明 |
|---|---|
| 靜態(tài)方法引用 | ClassName :: staticMethodName?例如上面的Math::abs |
| 構(gòu)造器引用 | ClassName :: new?例如通過(guò)Supplier?返回新實(shí)例 |
| 類任意實(shí)例方法引用 | ClassName :: instanceMethodName?例如?String::concat |
| 類特定實(shí)例方法引用 | instance:: instanceMethodName?例如?this::equals |
4. 關(guān)于可讀性問(wèn)題
大部分人認(rèn)為Lambda 表達(dá)式存在閱讀困難的問(wèn)題,其實(shí)不然,這種流水線的結(jié)構(gòu)恰恰增加了可讀性,每一個(gè)Lambda 表達(dá)式都可以看作一個(gè)執(zhí)行策略,方法引用反而讓你能更加清楚執(zhí)行了什么策略。另外我經(jīng)常見(jiàn)到類似如下的流式寫(xiě)法:
new?Random().ints(10)
????????.map(operand?->?{
????????????System.out.println("operand?=?"?+?operand);
????????????return?operand+1;
????????})
????????.forEach(System.out::println);
這種"大肚子"寫(xiě)法的風(fēng)格是不建議在函數(shù)式編程中出現(xiàn)的。最好單獨(dú)提出來(lái)封裝做方法引用,寫(xiě)成下面的風(fēng)格:
public?void?randomInt()?{
????new?Random().ints(10)
????????????.map(this::selfIncreasing)
????????????.forEach(System.out::println);
}
//?封裝
private?int?selfIncreasing(int?self){
????System.out.println("self?=?"?+?self);
????return?self+1;
}
這樣反而可讀性很強(qiáng),隨機(jī)取 10 個(gè)數(shù),然后每個(gè)數(shù)走個(gè)自增并分別打印出來(lái)。
5. 總結(jié)
方法引用實(shí)現(xiàn)在特定場(chǎng)景下Lambda 表達(dá)式的簡(jiǎn)化表示,目的在于讓代碼更加簡(jiǎn)潔。但是習(xí)慣了傳統(tǒng)Java編程風(fēng)格的同學(xué)上來(lái)會(huì)不太適應(yīng),希望借助于本文能幫助你解決這個(gè)問(wèn)題。
注下方公眾號(hào)獲取更多編程干貨

往期推薦
