Java方法的引用(打造Lambda表达式的升级版)
1.初入方法引用
2.通過對象名引用成員方法
3.通過類名引用靜態方法
4.通過super引用成員方法
5.通過this引用成員方法
6.類的構造器引用
7.數組的構造方法的引用
1.初入方法引用
1.冗余的Lambda表達式解決方案:
例子:
如果不懂Lambda可以參照這一篇博客:Lambda表達式詳解
分析上邊的代碼;
其中 prin 方法只管調用 printable 接口的 print 方法,而并不管 print 方法的具體實現邏輯會將字符串 打印到什么地方去。而 main 方法通過Lambda表達式指定了函數式接口 Printable 的具體操作方案為:拿到 String(類型可推導,所以可省略)數據后,在控制臺中輸出它。這段代碼的問題在于,對字符串進行控制臺打印輸出的操作方案,明明已經有了現成的實現,那就是 System.out 對象中的 println(String) 方法。既然Lambda希望做的事情就是調用 println(String) 方法,那何必自己手動調 用呢
啥意思呢看用方法引用的例子:
package untl1; public class MyPrint {public static void print(printable pri){pri.print("helloworld");}public static void main(String[] args) {print(System.out::println);} } @FunctionalInterface interface printable{void print(String str); } 運行結果: helloworld臥槽,這么高級
下面是對上邊代碼的解釋:
1.請注意其中的雙冒號::寫法,這被稱為“方法引用”,而雙冒號是一種新的語法,雙冒號 :: 為引用運算符,而它所在的表達式被稱為方法引用。如果Lambda要表達的函數方案已經存在于某個方 法的實現中,那么則可以通過雙冒號來引用該方法作為Lambda的替代者。
2.例如上例中, System.out 對象中有一個重載的 println(String) 方法恰好就是我們所需要的。那么對于 printString 方法的函數式接口參數,對于上邊的兩種寫法是等效的
對于例子中兩種寫法的對比:
| Lambda表達式 | s -> System.out.println(s); | 拿到參數之后經Lambda之手,繼而傳遞給 System.out.println 方法去處理。 |
| 方法引用 | System.out::println | 直接讓 System.out 中的 println 方法來取代Lambda。兩種寫法的執行效果完全一 樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。 注:Lambda 中 傳遞的參數 一定是方法引用中 的那個方法可以接收的類型,否則會拋出異常 |
如果使用Lambda,那么根據“可推導就是可省略”的原則,無需指定參數類型,也無需指定的重載形式——它們都 將被自動推導。而如果使用方法引用,也是同樣可以根據上下文進行推導。 函數式接口是Lambda的基礎,而方法引用是Lambda的孿生兄弟
上述的第二個例子就是把已經存在的System.out這個對象通過已經存在的printfln這個方法
再細品這句話:如果Lambda要表達的函數方案已經存在于某個方 法的實現中,那么則可以通過雙冒號來引用該方法作為Lambda的替代者。
2.通過對象名引用成員方法
其實和上邊的例子差不多再來一個例子:
package untl1; public class MyPrint {public void printString(String str){System.out.println(str.toUpperCase());}public static void prin(printable pri){pri.print("helloworld");}public static void main(String[] args) {MyPrint p=new MyPrint();prin(p::printString);}} @FunctionalInterface interface printable{void print(String str); } 運行結果: HELLOWORLD你品你細品:如果Lambda要表達的函數方案已經存在于某個方 法的實現中,那么則可以通過雙冒號來引用該方法作為Lambda的替代者。
3.通過類名引用靜態方法
我們分別用Lambda表達式和方法引用來舉例對比,求一個數的絕對值,然和再輸出
用Lambda表達式:
package untl1; public class MyPrint {public static void aaa(int num,printabs pri){System.out.println(pri.aboutabs(num));}public static void main(String[] args) {aaa(-100,num->Math.abs(num));} } @FunctionalInterface interface printabs{int aboutabs(int a); } 輸出結果: 100用方法的引用:
package untl1; public class MyPrint {public static void aaa(int num,printabs pri){System.out.println(pri.aboutabs(num));}public static void main(String[] args) {aaa(-100,Math::abs);} } @FunctionalInterface interface printabs{int aboutabs(int a); } 輸出結果: 1004.通過super引用成員方法
如果存在繼承關系,當Lambda中需要出現super調用時,也可以使用方法引用進行替代。
廢話不多說,先用Lambda舉例子:
package untl1; public class MyPrint extends human{public void sayhello(){System.out.println("hello我是human的兒子");}public void method(Greetable g){g.greet();}public void show(){method(()->{human h=new human();h.sayhello();});}public static void main(String[] args) {MyPrint p=new MyPrint();p.show();} }class human{public void sayhello(){System.out.println("hello,我是human");} } @FunctionalInterface interface Greetable{void greet(); } 運行結果: hello,我是human那么上邊的代碼用方法的引用:
package untl1; public class MyPrint extends human{public void sayhello(){System.out.println("hello我是human的兒子");}public void method(Greetable g){g.greet();}public void show(){method(super::sayhello);}public static void main(String[] args) {MyPrint p=new MyPrint();p.show();} }class human{public void sayhello(){System.out.println("hello,我是human");} } @FunctionalInterface interface Greetable{void greet(); } 運行結果: hello,我是human其實和對象引用方法名一樣的
5.通過this引用成員方法
this代表當前對象,如果需要引用的方法就是當前類中的成員方法,那么可以使用“this::成員方法”的格式來使用方法
package untl1; public class MyPrint extends human{public void sayhello(){System.out.println("hello我是human的兒子");}public void method(Greetable g){g.greet();}public void show(){method(this::sayhello);}public static void main(String[] args) {MyPrint p=new MyPrint();p.show();} }class human{public void sayhello(){System.out.println("hello,我是human");} } @FunctionalInterface interface Greetable{void greet(); } 輸出結果: hello我是human的兒子6.類的構造器的引用
由于構造器的名稱與類名完全一樣,并不固定。所以構造器引用使用 類名稱::new 的格式表示
例子(Lambda表達式):
package untl1; public class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public static void printname(String name,PersonBuilder per){System.out.println(per.buildPerson(name).getName());}public static void main(String[] args) {printname("哈哈",name->new Person(name));} } interface PersonBuilder {Person buildPerson(String name); } 運行結果: 哈哈用類構造器的引用:
package untl1; public class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public static void printname(String name,PersonBuilder per){System.out.println(per.buildPerson(name).getName());}public static void main(String[] args) {printname("哈哈",Person::new);} } interface PersonBuilder {Person buildPerson(String name); } 運行結果: 哈哈7.數組的構造器引用
數組也是 Object 的子類對象,所以同樣具有構造器,只是語法稍有不同
例子:
package untl1; public class Person {public static int[] createArray(int length,ArrayBuild ab){return ab.builderArray(length);}public static void main(String[] args) {// int arr[]=createArray(10,len->new int[len]);int arr[]=createArray(10,int[]::new);System.out.println(arr.length);} } interface ArrayBuild{int [] builderArray(int length); } 運行結果: 10總結
以上是生活随笔為你收集整理的Java方法的引用(打造Lambda表达式的升级版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java函数式接口看这一篇就够了
- 下一篇: Java资深反射玩家