日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java 8 - 05 方法引用

發(fā)布時(shí)間:2025/3/21 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 8 - 05 方法引用 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • Pre
  • 方法引用
    • 如何構(gòu)建方法引用
      • 指向靜態(tài)方法的方法引用
      • 指向任意類(lèi)型實(shí)例方法的方法引用
      • 指向現(xiàn)有對(duì)象的實(shí)例方法的方法引用
    • 構(gòu)造函數(shù)引用
    • 自定義構(gòu)造函數(shù)引用

Pre

先來(lái)看段代碼

Comparator<Enginner> enginnerComparator = new Comparator<Enginner>() {@Overridepublic int compare(Enginner o1, Enginner o2) {return o1.getJob().compareTo(o2.getJob());}};enginnerComparator.compare(new Enginner("Java",18),new Enginner("Go",10));List<Enginner> enginnerList = Arrays.asList(new Enginner("Java",18),new Enginner("Go",10));System.out.println("0enginnerList:" + enginnerList);enginnerList.sort(enginnerComparator);System.out.println("1enginnerList:" + enginnerList);

排序嘛 ,是不是很長(zhǎng)

使用方法引用,一行代碼搞定,如下:

enginnerList.sort(Comparator.comparing(Enginner::getJob));System.out.println("2enginnerList:" + enginnerList);

方法引用讓你可以重復(fù)使用現(xiàn)有的方法定義,并像Lambda一樣傳遞它們。在一些情況下比起使用Lambda表達(dá)式, 更易讀 。上面的栗子就是借助了Java 8 API ,用方法引用寫(xiě)的一個(gè)排序的例子。


方法引用

方法引用可以被看作僅僅調(diào)用特定方法的Lambda的一種快捷寫(xiě)法。它的基本思想是,如果一個(gè)Lambda代表的只是“直接調(diào)用這個(gè)方法”,那最好還是用名稱(chēng)來(lái)調(diào)用它,而不是去描述如何調(diào)用它。

實(shí)際上,方法引用就是讓你根據(jù)已有的方法實(shí)現(xiàn)來(lái)創(chuàng)建Lambda表達(dá)式。 顯式地指明方法的名稱(chēng),代碼的可讀性會(huì)更好 。

當(dāng)你需要使用方法引用時(shí),目標(biāo)引用放在分隔符 :: 前,方法的名稱(chēng)放在后面

Enginner::getJob

就是引用了 Enginner類(lèi)中定義的方法 getJob 。 請(qǐng)記住,不需要括號(hào),因?yàn)槟銢](méi)有實(shí)際調(diào)用這個(gè)方法。

方法引用就是Lambda表達(dá)式 (Enginnera) -> a.getJob() 的快捷寫(xiě)法

再來(lái)看幾個(gè)等效的例子 加深下印象

(Enginner a) -> a.getJob() 等價(jià)于 Enginner ::getJob

做下實(shí)驗(yàn)

public class MethodReferrenceDemo {public static <T, R> R doSomething(T t, Function<T, R> f) {return f.apply(t);}public static void main(String[] args) {Function<Enginner, String> ef = (Enginner e) -> e.getJob();System.out.println(doSomething(new Enginner("Java", 18), ef));Function<Enginner, String> ef2 = Enginner::getJob;System.out.println(doSomething(new Enginner("Java", 18), ef2));} }

還比如

() -> Thread.currentThread().dumpStack() 等價(jià)于 Thread.currentThread()::dumpStack (str, i) -> str.substring(i) 等價(jià)于 String::substring (String s) -> System.out.println(s) 等價(jià)于 System.out::println

我們可以把方法引用看作針對(duì)僅僅涉及單一方法的Lambda的語(yǔ)法糖,因?yàn)槟惚磉_(dá)同樣的事情
時(shí)要寫(xiě)的代碼更少了。


如何構(gòu)建方法引用

方法引用主要有三類(lèi)。

指向靜態(tài)方法的方法引用

舉個(gè)例子 : Integer 的 parseInt 方法,寫(xiě)作 Integer::parseInt

Function<String, Integer> stringIntegerFunction2 = (String s) -> Integer.parseInt(s);Function<String, Integer> stringIntegerFunction3 = Integer::parseInt;System.out.println(stringIntegerFunction2.apply("18"));System.out.println(stringIntegerFunction3.apply("18"));

指向任意類(lèi)型實(shí)例方法的方法引用

舉個(gè)例子 : String 的 length 方 法 , 寫(xiě) 作 String::length

Function<String, Integer> stringIntegerFunction = (String s) -> s.length();Function<String, Integer> stringIntegerFunction1 = String::length;System.out.println(stringIntegerFunction.apply("abc"));System.out.println(stringIntegerFunction1.apply("abc"));

類(lèi)似于 String::length 方法引用的思想就是你在引用一個(gè)對(duì)象的方法,而這個(gè)對(duì)象本身是Lambda的一個(gè)參數(shù)。

例如,Lambda表達(dá)式 (String s) -> s.toUppeCase() 可以寫(xiě)作 String::toUpperCase


指向現(xiàn)有對(duì)象的實(shí)例方法的方法引用

假設(shè)你有一個(gè)局部變量 eng用于存放 Enginner 類(lèi)型的對(duì)象,它支持實(shí)例方法 getValue ,那么你就可以寫(xiě) eng::getValue

這種寫(xiě)法是我們?cè)贚ambda中調(diào)用一個(gè)已經(jīng)存在的外部對(duì)象中的方法。 例如,Lambda表達(dá)式()->eng.getValue() 可以寫(xiě)作 eng::getValue 。


再來(lái)看幾個(gè)例子, 將Lambda表達(dá)式重構(gòu)為等價(jià)的方法引用

lambda : args -> ClassName.staticMethod(args)等價(jià)于 (1)方法引用: className::staticMethod lambda : (arg0 ,rest)-> argo.instanceMethod(rest) (arg0是ClassName類(lèi)型的)等價(jià)于 (2)方法引用: ClassName::instanceMethod lambda : (args)-> expr.instanceMethod(args) 等價(jià)于方法引用: expr::instanceMethod

請(qǐng)注意,還有針對(duì)構(gòu)造函數(shù)、數(shù)組構(gòu)造函數(shù)和父類(lèi)調(diào)用(super-call)的一些特殊形式的方法引用。

比方說(shuō)你想要對(duì)一個(gè)字符串的 List 排序,忽略大小寫(xiě)。 List 的 sort 方法需要一個(gè) Comparator 作為參數(shù) 。 我們知道 Comparator 描述了 一個(gè)具有 (T, T) -> int 簽名的函數(shù)描述符。你可以利用 String 類(lèi)中的 compareToIgnoreCase方法來(lái)定義一個(gè)Lambda表達(dá)式。

List<String> list = Arrays.asList("apple","pear","banana");list.sort((s1,s2)-> s1.compareToIgnoreCase(s2));

Lambda表達(dá)式的簽名與 Comparator 的函數(shù)描述符兼容。利用前面所述的方法,這個(gè)例子可以使用方法引用改成下面的樣子

list.sort(String::compareToIgnoreCase);

請(qǐng)注意,編譯器會(huì)進(jìn)行一種與Lambda表達(dá)式類(lèi)似的類(lèi)型檢查過(guò)程,來(lái)確定對(duì)于給定的函數(shù)式接口,這個(gè)方法引用是否有效:方法引用的簽名必須和上下文類(lèi)型匹配

來(lái)個(gè)小測(cè)驗(yàn)吧

測(cè)驗(yàn):方法引用 下列Lambda表達(dá)式的等效方法引用是什么?(1) Function<String, Integer> stringToInteger = (String s) -> Integer.parseInt(s); (2) BiPredicate<List<String>, String> contains = (list, element) -> list.contains(element);答案如下。 (1) 這個(gè)Lambda表達(dá)式將其參數(shù)傳給了 Integer 的靜態(tài)方法 parseInt 。這種方法接受一 個(gè)需要解析的 String ,并返回一個(gè) Integer 。因此,可以使用 Lambda表達(dá)式調(diào)用靜態(tài)方法來(lái)重寫(xiě)Lambda表達(dá)式,如下所示: Function<String, Integer> stringToInteger = Integer::parseInt;(2) 這個(gè)Lambda使用其第一個(gè)參數(shù),調(diào)用其 contains 方法。由于第一個(gè)參數(shù)是 List 類(lèi)型 的,你可以使用剛才的(2) 如下: BiPredicate<List<String>, String> contains = List::contains;這是因?yàn)?#xff0c;目標(biāo)類(lèi)型描述的函數(shù)描述符是 (List<String>,String) -> boolean ,而 List::contains 可以被解包成這個(gè)函數(shù)描述符。

構(gòu)造函數(shù)引用

對(duì)于一個(gè)現(xiàn)有構(gòu)造函數(shù),我們可以利用它的名稱(chēng)和關(guān)鍵字 new 來(lái)創(chuàng)建它的一個(gè)引用:ClassName::new 。它的功能與指向靜態(tài)方法的引用類(lèi)似。

例如,假設(shè)有一個(gè)構(gòu)造函數(shù)沒(méi)有參數(shù)。它適合 Supplier 的簽名 () -> Enginner。

Enginner的構(gòu)造函數(shù)

我們可以這樣做:

// 構(gòu)造函數(shù)引用指向默認(rèn)Enginner的構(gòu)造函數(shù)Supplier<Enginner> supplier = Enginner::new;// 調(diào)用 Supplier 的 get 方法 將產(chǎn)生一個(gè)新的 enginner Enginner enginner = supplier.get();

等價(jià)于

Supplier<Enginner> s = () -> new Enginner();// 利用默認(rèn)構(gòu)造函數(shù)創(chuàng)建 Enginner的Lambda表達(dá)式Enginner supplier2 = s.get();// 調(diào)用 Supplier 的 get 方法 將產(chǎn)生一個(gè)新的 Enginner

如果Enginner構(gòu)造函數(shù)的簽名是 Enginner(String job) ,那么它就適合 Function 接口的簽
名,我們可以這樣寫(xiě):

// 指向 Enginner(String job) 的構(gòu)造函數(shù)引用Function<String ,Enginner> f2 = Enginner::new; // 調(diào)用該 Function 函數(shù)的 apply 方法,并給出職位,將產(chǎn)生一個(gè) Enginner Enginner e2 =f2.apply("Java");System.out.println(e2.getJob());

如果你有一個(gè)具有兩個(gè)參數(shù)的構(gòu)造函數(shù) Enginner(String job, Integer age) ,那么
它就適合 BiFunction 接口的簽名 . 兩個(gè)參數(shù)的 使用BiFunction 即可 (Bi = Binary )

BiFunction<String ,Integer,Enginner> f3 = Enginner::new;Enginner e4 = f3.apply("Java",18);System.out.println(e4 .getJob() + " - " + e4.getAge());

上面是使用方法引用,如果直接用lambda呢? 如下

BiFunction<String,Integer,Enginner> f4 = (str , age)-> new Enginner(str, age);Enginner ee =f4.apply("Go", 10);System.out.println(ee .getJob() + " - " + ee.getAge());


自定義構(gòu)造函數(shù)引用

上面的栗子我們將有零個(gè)、一個(gè)、兩個(gè)參數(shù)的構(gòu)造函數(shù)轉(zhuǎn)變?yōu)闃?gòu)造函數(shù)引用。那要怎么樣才能對(duì)具有三個(gè)參數(shù)的構(gòu)造函數(shù),比如 Color(int, int, int), 使用構(gòu)造函數(shù)引用呢?

構(gòu)造函數(shù)引用的語(yǔ)法是 ClassName::new ,那么在這個(gè)例子里面就是Color::new 。但是你需要與構(gòu)造函數(shù)引用的簽名匹配的函數(shù)式接口。但是語(yǔ)言本身并沒(méi)有提供這樣的函數(shù)式接口,你可以自己創(chuàng)建一個(gè):

public interface TriFunction<T, U, V, R>{R apply(T t, U u, V v); }

現(xiàn)在你可以像下面這樣使用構(gòu)造函數(shù)引用了:

TriFunction<Integer, Integer, Integer, Color> colorFactory = Color::new;

總結(jié)

以上是生活随笔為你收集整理的Java 8 - 05 方法引用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。