方法引用基本介绍
在使用Lambda表達式的時候,我們實際上傳遞進去的代碼就是一種解決方案:拿什么參數做什么操作。那么考慮
一種情況:如果我們在Lambda中所指定的操作方案,已經有地方存在相同方案,那是否還有必要再寫重復邏輯?
冗余的Lambda場景
來看一個簡單的函數式接口以應用Lambda表達式:
package com.learn.demo04.MethodReference; /*定義一個打印的函數式接口*/ @FunctionalInterface public interface Printable {//定義字符串的抽象方法void print(String s); }在Printable 接口當中唯一的抽象方法print 接收一個字符串參數,目的就是為了打印顯示它。那么通過Lambda
來使用它的代碼很簡單:
其中printString 方法只管調用Printable 接口的print 方法,而并不管print 方法的具體實現邏輯會將字符串
打印到什么地方去。而main 方法通過Lambda表達式指定了函數式接口Printable 的具體操作方案為:拿到
String(類型可推導,所以可省略)數據后,在控制臺中輸出它。
問題分析
這段代碼的問題在于,對字符串進行控制臺打印輸出的操作方案,明明已經有了現成的實現,那就是System.out
對象中的println(String) 方法。既然Lambda希望做的事情就是調用println(String) 方法,那何必自己手動調
用呢?
用方法引用改進代碼
能否省去Lambda的語法格式(盡管它已經相當簡潔)呢?只要“引用”過去就好了:
public class Demo02PrintRef { private static void printString(Printable data) { data.print("Hello, World!"); } public static void main(String[] args) { printString(System.out::println); } }請注意其中的雙冒號:: 寫法,這被稱為“方法引用”,而雙冒號是一種新的語法。
方法引用符
雙冒號:: 為引用運算符,而它所在的表達式被稱為方法引用。如果Lambda要表達的函數方案已經存在于某個方
法的實現中,那么則可以通過雙冒號來引用該方法作為Lambda的替代者。
語義分析
例如上例中, System.out 對象中有一個重載的println(String) 方法恰好就是我們所需要的。那么對于
printString 方法的函數式接口參數,對比下面兩種寫法,完全等效:
Lambda表達式寫法: s -> System.out.println(s);
方法引用寫法: System.out::println
第一種語義是指:拿到參數之后經Lambda之手,繼而傳遞給System.out.println 方法去處理。
第二種等效寫法的語義是指:直接讓System.out 中的println 方法來取代Lambda。兩種寫法的執行效果完全一
樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。
注:Lambda 中 傳遞的參數 一定是方法引用中 的那個方法可以接收的類型,否則會拋出異常
推導與省略
如果使用Lambda,那么根據“可推導就是可省略”的原則,無需指定參數類型,也無需指定的重載形式——它們都
將被自動推導。而如果使用方法引用,也是同樣可以根據上下文進行推導。
函數式接口是Lambda的基礎,而方法引用是Lambda的孿生兄弟。
下面這段代碼將會調用println 方法的不同重載形式,將函數式接口改為int類型的參數:
由于上下文變了之后可以自動推導出唯一對應的匹配重載,所以方法引用沒有任何變化:
public class Demo03PrintOverload { private static void printInteger(PrintableInteger data) { data.print(1024); } public static void main(String[] args) { printInteger(System.out::println); } }這次方法引用將會自動匹配到println(int) 的重載形式。
?
?
?
?
?
?
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
- 上一篇: 集合元素处理(Stream方式)
- 下一篇: 方法引用_通过对象名引用成员方法