我們都是陰溝里的蟲子,但總還是得有人仰望星空。——《三體》
在之前的文章中介紹了Lambda表達式的基本語法和正確使用姿勢,這次我來介紹一些Lambda更簡潔的用法。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
類型推斷
編譯器可以通過函數式接口推斷出Lambda表達式的參數類型,所以在編寫Lambda表達式時,可以省略參數類型。比如:
Comparator<Mask> comparator = (Mask o1, Mask o2) -> o1.getBrand().compareTo(o2.getBrand());
就可以簡寫為:
Comparator<Mask> comparator = (o1, o2) -> o1.getBrand().compareTo(o2.getBrand());
另外,當Lambda表達式只有一個參數的時候,不僅可以省略參數類型,還可以省略到參數名稱兩邊的括號,比如:
Predicate<Mask> predicate = (Mask mask) -> mask.getType() == "N95";
就可以簡寫為:
Predicate<Mask> predicate = mask -> mask.getType() == "N95";
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
方法引用
什么是方法引用?
方法引用是Java8中引入的新特性,它提供了一種引用方法而不執行方法的方式,可以讓我們重復使用現用方法的定義,做為某些Lambda表達式的另一種更簡潔的寫法。
比如前面的例子:
Comparator<Mask> comparator = (o1, o2) -> o1.getBrand().compareTo(o2.getBrand());
使用方法引用以后,可以簡寫為:
Comparator<Mask> comparator = Comparator.comparing(Mask::getBrand);
當你需要方法引用時,目標引用放在分隔符::
前,方法的名稱放在分隔符::
后。比如,上面的Mask::getBrand
,就是引用了Mask
中定義的getBrand
方法。方法名稱后不需要加括號,因為我們並沒有實際調用它。方法引用提高了代碼的可讀性,也使邏輯更加清晰。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
怎么構建方法引用?
可以構建方法引用的場景的有四種:
1. 靜態方法
指向靜態方法的引用,語法:類名::靜態方法名
,類名放在分隔符::
前,:靜態方法名放在分隔符::
后。比如:
(String str) -> Integer.parseInt(str)
使用方法引用以后,可以簡寫為:
Integer::parseInt
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
2. 內部對象的實例方法
指向Lambda表達式內部對象的實例方法的引用,語法:類名::實例方法名
,類名放在分隔符::
前,:實例方法名放在分隔符::
后。比如:
(Mask mask) -> mask.getBrand()
使用方法引用以后,可以簡寫為:
Mask::getBrand
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
3. 外部對象的實例方法
指向Lambda表達式外部對象的實例方法的引用,語法:實例名::實例方法名
,類名放在分隔符::
前,:實例方法名放在分隔符::
后。比如:
String type = "N95";
Predicate<String> predicate = (String str) -> type.equals(str);
System.out.println(predicate.test("N95"));
其中,type
是一個Lambda表達式外部的局部變量,使用方法引用以后,可以簡寫為:
String type = "N95";
Predicate<String> predicate = type::equals;
System.out.println(predicate.test("N95"));
如果對於Predicate
接口還不熟悉,沒關系,以后的文章會介紹到,這里暫且知道它的抽象方法的簽名是(T) -> boolean
就可以了。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
4. 構造方法
指向構造方法的引用,語法:類名::new
,類名放在分隔符::
前,new
放在分隔符::
后。比如:
(String brand, String type) -> new Mask(brand, type)
使用方法引用以后,可以簡寫為:
Mask::new
小測試
看了這么多,是不是摩拳擦掌准備試一試了?我們就來一個小測試:
(char[] array) -> new String(array)
(String str) -> str.length()
(String type) -> mask.setType(type)
,其中的mask
是一個Mask
對象的局部變量。(String str) -> System.out.println(str)
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
請思考片刻…
.
.
.
.
.
.
宣布答案:
- 因為
(char[] array) -> new String(array)
是一個構造方法的Lambda表達式,此種方法引用的語法是:類名::new
,所以正確答案是:String::new
。 - 因為
(String str) -> str.length()
是一個內部對象的實例方法的Lambda表達式,此種方法引用的語法是:類名::實例方法名
,所以正確答案是:String::length
。 - 因為
(String type) -> mask.setType(type)
中的mask
是一個Mask
對象的局部變量,它是一個包含外部對象的Lambda表達式,此種方法引用的語法是:實例名::實例方法名
,所以正確答案是mask::setType
。 - 因為
(String str) -> System.out.println(str)
是一個靜態方法的Lambda表達式,此種方法引用的語法是:類名::靜態方法名
,所以正確答案是System.out::println
。
怎么樣?都答對了嘛?
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。
《死磕Lambda表達式》系列
- 死磕Lambda表達式(一):初識Lambda
- 死磕Lambda表達式(二):Lambda的使用
- 死磕Lambda表達式(三):更簡潔的Lambda
- 死磕Lambda表達式(四):常用的函數式接口
- 死磕Lambda表達式(五):Comparator復合
- 死磕Lambda表達式(六):Consumer、Predicate、Function復合
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術干貨。