摘要:實際上方法引用是表達式的一種語法糖。小結本篇全面介紹了方法引用的四種使用方式,且每種方式都有對應一個示例來幫助大家理解。
上一篇我們詳細介紹了Optional類用來避免空指針問題,本篇我們全面了解一下Java8中的方法引用特性。
方法引用是lambda表達式的一種特殊形式,如果正好有某個方法滿足一個lambda表達式的形式,那就可以將這個lambda表達式用方法引用的方式表示,但是如果這個lambda表達式的比較復雜就不能用方法引用進行替換。實際上方法引用是lambda表達式的一種語法糖。
在介紹方法引用使用方式之前,先將方法引用分下類
方法引用共分為四類:
1.類名::靜態方法名
2.對象::實例方法名
3.類名::實例方法名
4.類名::new
首先來看下第一種 類名::靜態方法名 為了演示我們自定義了一個Student類
public class Student { private String name; private int score; public Student(){ } public Student(String name,int score){ this.name = name; this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public static int compareStudentByScore(Student student1,Student student2){ return student1.getScore() - student2.getScore(); } }
Student類有兩個屬性name和score并提供了初始化name和score的構造方法,并且在最下方提供了兩個靜態方法分別按score和name進行比較先后順序。
接下來的需求是,按著分數由小到大排列并輸出,在使用方法引用前,我們先使用lambda表達式的方式進行處理
Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); Liststudents = Arrays.asList(student1,student2,student3,student4); students.sort((o1, o2) -> o1.getScore() - o2.getScore()); students.forEach(student -> System.out.println(student.getScore()));
sort方法接收一個Comparator函數式接口,接口中唯一的抽象方法compare接收兩個參數返回一個int類型值,下方是Comparator接口定義
@FunctionalInterface public interface Comparator{ int compare(T o1, T o2); }
我們再看下Student類中定義的compareStudentByScore靜態方法
public static int compareStudentByScore(Student student1,Student student2){ return student1.getScore() - student2.getScore(); }
同樣是接收兩個參數返回一個int類型值,而且是對Student對象的分數進行比較,所以我們這里就可以 使用類名::靜態方法名 方法引用替換lambda表達式
students.sort(Student::compareStudentByScore); students.forEach(student -> System.out.println(student.getScore()));
第二種 對象::實例方法名
我們再自定義一個用于比較Student元素的類
public class StudentComparator { public int compareStudentByScore(Student student1,Student student2){ return student2.getScore() - student1.getScore(); } }
StudentComparator中定義了一個非靜態的,實例方法compareStudentByScore,同樣該方法的定義滿足Comparator接口的compare方法定義,所以這里可以直接使用 對象::實例方法名 的方式使用方法引用來替換lambda表達式
StudentComparator studentComparator = new StudentComparator(); students.sort(studentComparator::compareStudentByScore); students.forEach(student -> System.out.println(student.getScore()));
第三種 類名::實例方法名
這種方法引用的方式較之前兩種稍微有一些不好理解,因為無論是通過類名調用靜態方法還是通過對象調用實例方法這都是符合Java的語法,使用起來也比較清晰明了。那我們帶著這個疑問來了解一下這個比較特殊的方法引用。
現在再看一下Student類中靜態方法的定義
public static int compareStudentByScore(Student student1,Student student2){ return student1.getScore() - student2.getScore(); }
雖然這個方法在語法上沒有任何問題,可以作為一個工具正常使用,但是有沒有覺得其在設計上是不合適的或者是錯誤的。這樣的方法定義放在任何一個類中都可以正常使用,而不只是從屬于Student這個類,那如果要定義一個只能從屬于Student類的比較方法下面這個實例方法更合適一些
public int compareByScore(Student student){ return this.getScore() - student.getScore(); }
接收一個Student對象和當前調用該方法的Student對象的分數進行比較即可?,F在我們就可以使用 類名::實例方法名 這種方式的方法引用替換lambda表達式了
students.sort(Student::compareByScore); students.forEach(student -> System.out.println(student.getScore()));
這里非常奇怪,sort方法接收的lambda表達式不應該是兩個參數么,為什么這個實例方法只有一個參數也滿足了lambda表達式的定義(想想這個方法是誰來調用的)。這就是 類名::實例方法名 這種方法引用的特殊之處:當使用 類名::實例方法名 方法引用時,一定是lambda表達式所接收的第一個參數來調用實例方法,如果lambda表達式接收多個參數,其余的參數作為方法的參數傳遞進去。
結合本例來看,最初的lambda表達式是這樣的
students.sort((o1, o2) -> o1.getScore() - o2.getScore());
那使用 類名::實例方法名 方法引用時,一定是o1來調用了compareByScore實例方法,并將o2作為參數傳遞進來進行比較。是不是就符合了compareByScore的方法定義。
第四種 類名::new
也稱構造方法引用,和前兩種類似只要符合lambda表達式的定義即可,回想下Supplier函數式接口的get方法,不接收參數有返回值,正好符合無參構造方法的定義
@FunctionalInterface
public interface Supplier
/** * Gets a result. * * @return a result */ T get();
}
Suppliersupplier = Student::new;
上面就是使用了Student類構造方法引用創建了supplier實例,以后通過supplier.get()就可以獲取一個Student類型的對象,前提是Student類中存在無參構造方法。
小結:本篇全面介紹了方法引用的四種使用方式,且每種方式都有對應一個示例來幫助大家理解。當我們使用lambda表達式進行函數式編程時,如果某個方法正好滿足lambda的定義,也滿足實際需求的邏輯,就可以使用方法引用的方式來替換lambda表達式。接下來我們將真正開始學習stream api,并結合前面學習的內容體驗stream api的強大之處。
下一篇
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70722.html
摘要:不是引用類型,無法輸出簡而言之,堆內存存放引用值,棧內存存放固定類型值。變量的查詢在變量的查詢中,訪問局部變量要比全局變量來得快,因此不需要向上搜索作用域鏈。 贊助我以寫出更好的文章,give me a cup of coffee? 2017最新最全前端面試題 基本類型值有:undefined,NUll,Boolean,Number和String,這些類型分別在內存中占有固定的大小空...
摘要:也就是說當使用后,當前執行上下文中的對象已被替換為,后續執行將以所持有的狀態屬性繼續執行。借用的方法替換的實例去調用相應的方法。實現引用類型的繼承其實沒有類這一概念,我們平時使用的等嚴格來說被稱作引用類型。 call 方法:object.method.call(targetObj[, argv1, argv2, .....]) apply 方法:object.method.apply(...
摘要:事實上,最新的已經支持了私有屬性。而的私有方法是提案的一部分。自從年雙十一正式上線,累計處理了億錯誤事件,付費客戶有金山軟件百姓網等眾多品牌企業。 譯者按: 為什么偏要用#符號? 原文:JavaScripts new #private class fields 譯者:Fundebug 本文采用意譯,版權歸原作者所有 proposal-class-fields與proposa...
摘要:類型使用自,國際協調時間年月日午夜零時開始經過的毫秒數來保存日期。日期時間組件方法到目前為止,剩下還未介紹的類型的方法如下表所示,都是直接取得和設置日期值中特定部分的方法了。 Date類型使用自UTC(Coordinated Universal Time,國際協調時間)1970 年1 月1 日午夜(零時)開始經過的毫秒數來保存日期。在使用這種數據存儲格式的條件下,Date 類型保存的日...
摘要:前兩天看到大神的關于基本數據類型和引用類型的區別的文章覺得寫得非常不錯,就想著在其基礎上加上自己平時看到的一些知識點和理解,所以就有了以下的文章基本數據類型基本數據類型包括基本數據類型是按值訪問的,就是說我們可以操作保存在變量中的實際的值基 前兩天看到kraaas大神的關于基本數據類型和引用類型的區別的文章覺得寫得非常不錯,就想著在其基礎上加上自己平時看到的一些知識點和理解,所以就有了...
閱讀 895·2021-09-22 15:17
閱讀 1918·2021-09-22 15:06
閱讀 2219·2021-09-08 09:35
閱讀 5105·2021-09-01 11:43
閱讀 3480·2019-08-30 15:55
閱讀 2154·2019-08-30 12:48
閱讀 3155·2019-08-30 12:45
閱讀 1784·2019-08-29 17:31