Lambda 表達(dá)式的引用
所謂 Lambda 表達(dá)式的方法引用可以理解為 Lambda 表達(dá)式的一種快捷寫法,相較于通常的 Lambda 表達(dá)式而言有著更高的可讀性和重用性。
Tips: 一般而言,方法實(shí)現(xiàn)比較簡(jiǎn)單、復(fù)用地方不多的時(shí)候推薦使用通常的 Lambda 表達(dá)式,否則應(yīng)盡量使用方法引用。
Lambda 表達(dá)式的引用分為:方法引用 和 構(gòu)造器引用兩類。
方法引用的格式為:
類名::方法名
::
是引用的運(yùn)算符,其左邊是類名,右邊則是引用的方法名。
構(gòu)造器引用的格式為:
類名::new
同樣,::
是引用的運(yùn)算符,其左邊是類名,右邊則是使用關(guān)鍵字 new
表示調(diào)用該類的構(gòu)造函數(shù)。構(gòu)造器引用是一種特殊的引用。
通常引用語法格式有以下 3 種:
- 靜態(tài)方法引用;
- 參數(shù)方法引用;
- 實(shí)例方法引用。
接下來我們堆上述 3 種引用逐一進(jìn)行講解。
1. 靜態(tài)方法引用
所謂靜態(tài)方法應(yīng)用就是調(diào)用類的靜態(tài)方法。
Tips:
- 被引用的參數(shù)列表和接口中的方法參數(shù)一致;
- 接口方法沒有返回值的,引用方法可以有返回值也可以沒有;
- 接口方法有返回值的,引用方法必須有相同類型的返回值。
我們來看一個(gè)例子:
public interface Finder {
public int find(String s1, String s2);
}
這里我們定義了一個(gè) Finder
接口,其包含一個(gè)方法 find
,兩個(gè) String
類型的輸入?yún)?shù),方法返回值為 int
類型。
隨后,我們創(chuàng)建一個(gè)帶有靜待方法的類 StaticMethodClass
:
//創(chuàng)建一個(gè)帶有靜態(tài)方法的類
public class StaticMethodClass{
public static int doFind(String s1, String s2){
return s1.lastIndexOf(s2);
}
}
在 StaticMethodClass
類中,我們查找最后一次出現(xiàn)在字符串 s1
中的 s2
的位置。
在這里
Finder
接口的find
方法和類StaticMethodClass
的doFind
方法有相同的輸入?yún)?shù)(參數(shù)個(gè)數(shù)和類型)完全相同,又因?yàn)?doFind
方法是一個(gè)靜態(tài)方法,于是我們就可以使用靜態(tài)方法引用了。
最后,我們?cè)?Lambda 表達(dá)式使用這個(gè)靜態(tài)引用:
Finder finder = StaticMethodClass :: doFind;
此時(shí),Finder
接口引用了 StaticMethodClass 的靜態(tài)方法 doFind。
2. 參數(shù)方法引用
參數(shù)方法引用顧名思義就是可以將參數(shù)的一個(gè)方法引用到 Lambda 表達(dá)式中。
Tips: 接口方法和引用方法必須有相同的 參數(shù) 和 返回值。
同樣我們使用前面的 Finder 接口為例:
public interface Finder {
public int find(String s1, String s2);
}
我們希望 Finder
接口搜索參數(shù) s1
的出現(xiàn)參數(shù) s2
的位置,這個(gè)時(shí)候我們會(huì)使用 Java String 的 indexOf 方法 String.indexOf
來進(jìn)行查詢,通常我們是這么使用 Lambda 表達(dá)式的:
Finder finder =(s1,s2)-> s1.indexOf(s2);
我們發(fā)現(xiàn),接口 Finder
的 find
方法與 String.indexOf
有著相同的方法簽名(相同的輸入和返回值),那么我們就可以使用參數(shù)方法引用來進(jìn)一步簡(jiǎn)化:
//參數(shù)方法引用
Finder finder = String :: indexOf;
//調(diào)用find方法
int findIndex = finder.find("abc","bc")
//輸出find結(jié)果。
System.out.println("返回結(jié)果:"+findIndex)
輸出為:
返回結(jié)果:2
此時(shí),編譯器會(huì)使用參數(shù) s1
為引用方法的參數(shù),將引用方法與 Finder
接口的 find
方法進(jìn)行類型匹配,最終調(diào)用 String 的 indexOf 方法。
3. 實(shí)例方法引用
實(shí)例方法引用就是直接調(diào)用實(shí)例的方法。
Tips: 接口方法和實(shí)例的方法必須有相同的參數(shù)和返回值。
我們來看一例子:
首先我們定義一個(gè)序列化接口:
public interface Serializer {
public int serialize(String v1);
}
然后我們定一個(gè)轉(zhuǎn)換類 StringConverter:
public class StringConverter {
public int convertToInt(String v1){
return Integer.valueOf(v1);
}
}
這個(gè)時(shí)候 Serializer.serialize
方法和 StringConvertor.converToInt
有著相同的方法簽名(即,輸入和輸出都是相同的),那么,我們可以創(chuàng)建一個(gè) StringConvertor
的實(shí)例,并通過 Lambda 表達(dá)式將其并引用給 convertToInt()
方法。
StringConverter stringConverter = new StringConverter();
Serializer serializer = StringConverter::convertToInt;
我們?cè)诘谝恍写a中創(chuàng)建了 StringConverter
的對(duì)象,在第二行代碼中,通過 實(shí)例方法引用來引用 StringConverter
的 convertToInt
方法。
4. 構(gòu)造器引用
構(gòu)造器引用便是引用一個(gè)類的構(gòu)造函數(shù)
Tips: 接口方法和對(duì)象構(gòu)造函數(shù)的參數(shù)必須相同。
其格式如下:
類名 :: new
我們來看一個(gè)例子:
public interfact MyFactory{
public String create(char[] chars)
}
我們定義了 MyFactory
接口 有一個(gè) create
方法,接收一個(gè) char[]
類型的輸入?yún)?shù),返回值類型為 String
, 它與 String(char[] chars)
這個(gè) String
的構(gòu)造函數(shù)有著相同的方法簽名。這個(gè)時(shí)候我們就可以使用構(gòu)造器引用了:
MyFactory myfactory = String::new;
它等價(jià)于 Lambda 表達(dá)式:
MyFactory myfactory = chars->new String(chars);
5. 小結(jié)

本節(jié)我們主要學(xué)習(xí)了 Lambda 表達(dá)式的引用,引用是基于方法調(diào)用的事實(shí)提供一種簡(jiǎn)短的語法,讓我們無需看完整的代碼就能弄明白代碼的意圖。