在上一篇文章中我們介紹了JDK1.8的新特性有以下幾項。 1.Lambda表達式 2.方法引用 3.函數式介面 4.預設方法 5.Stream 6.Optional類 7.Nashorm javascript引擎 8.新的日期時間API 9.Base64 並且學習了JDK1.8最重要的特性--Lam ...
在上一篇文章中我們介紹了JDK1.8的新特性有以下幾項。
3.函數式介面
4.預設方法
5.Stream
6.Optional類
7.Nashorm javascript引擎
8.新的日期時間API
9.Base64
並且學習了JDK1.8最重要的特性--Lambda表達式,這一篇學習方法引用。
首先介紹方法引用是啥?
方法引用單從“引用”二字不難理解,我們經常拿毛主席的”不管黑貓白貓能抓住老鼠的貓就是好貓“這句話來說事情,這裡就是引用了毛主席的話。那麼方法引用就是拿過其他地方已經存在的方法,我們拿過來使用,在這裡可以理解成Lambda表達式的一種特殊用法。只是我們得按照一定的規則來用。也就是我們接下來要重點要學習的內容:方法引用的方式
接下來先列出方法引用的方式。
總體來說方法引用有三種方式,分別如下。
1.普通方法引用
1.1 實例方法引用(通過實例對象)
對象::實例方法名;
1.2 靜態方法引用
類名::靜態方法名;
1.3 實例方法引用(通過類名)
類名::實例方法名;
註:上面兩種實例方法引用的不同之處,通過下麵代碼詳細說明。
2.構造器引用
類名::new;
3.數組引用
類型::new;
下麵重點通過實例來學習上面的集中形式。
1.1 實例方法引用(通過實例對象)
下麵通過最簡單的列印輸出語句來理解實例方法引用。
1 public class MethodReferenceTest { 2 3 /** 4 * 為了更容易理解方法引用 5 * 我通過正常的Lambda表達式和方法引用兩種方式來實現代碼部分 6 */ 7 //***************************** 8 // 方法引用的形式一 對象::實例方法名 9 //***************************** 10 @Test 11 public void test1(){ 12 //Lambda表達式 13 PrintStream ps1 = System.out; 14 Consumer con1 = x -> ps1.println(x); 15 con1.accept("Hello Lambda表達式!"); 16 17 //方法引用 18 PrintStream ps2 = System.out; 19 Consumer con2 = ps2::println; 20 con2.accept("Hello 方法引用!"); 21 } 22 23 }
執行結果
...
com.dream.test.JDK8speciality.MethodReferenceTest,test1
Hello Lambda表達式!
Hello 方法引用!
Process finished with exit code 0
通過上面實例14行和19行的對比可以看出,使用方法引用的方式比直接Lambda表達式更簡潔,再次也可以看做方法引用是Lambda表達式的一種特殊寫法,學習了Lambda表達式,方法引用的寫法也就不難理解了。
註:Consumer是JDK1.8的java.util.function包下提供的一個函數式介面,accept方法接收一個泛型<T>類型,返回值為void的抽象方法。具體實現是Lambda表達式的部分去實現的,也就是 x -> ps1.println(x); 和 ps2::println; 關於JDK1.8提供的函數式介面會在後面函數式介面章節進行學習。
1.2 靜態方法引用
下麵通過比較兩個整數的大小來理解靜態方法的引用。
1 public class MethodReferenceTest { 2 3 //***************************** 4 // 方法引用的形式二 類名::靜態方法名 5 //***************************** 6 @Test 7 public void test2(){ 8 //Lambda表達式 9 //x > y:返回1; 10 //x = y:返回0; 11 //x < y:返回-1; 12 Comparator<Integer> com1 = (x,y)->Integer.compare(x,y); 13 Integer i1=com1.compare(2,1); 14 System.out.println("Lambda表達式結果:" + i1); 15 16 //方法引用 17 Comparator<Integer> com2 = Integer::compare; 18 Integer i2=com2.compare(2,1); 19 System.out.println("方法引用結果:" + i2); 20 } 21 22 }
執行結果
com.dream.test.JDK8speciality.MethodReferenceTest,test2
Lambda表達式結果:1
方法引用結果:1
Process finished with exit code 0
正常通過Lam表達式我們 (x,y)->Integer.compare(x,y);這樣寫,由於Integer類下有靜態方法已經實現了兩個整數的比較,所有我們通過靜態方法引用的方式直接引用就好了。由此變成了Integer::compare;
1.3 實例方法引用(通過類名)
通過比較兩個字元串的內容來說明。
1 public class MethodReferenceTest { 2 3 //***************************** 4 // 方法引用的形式三 類名::實例方法 5 //***************************** 6 @Test 7 public void test3(){ 8 //比較兩個字元串的內容 9 //Lambda表達式 10 BiPredicate<String,String> bp1 = (s1,s2) -> s1.equals(s2); 11 boolean b1 = bp1.test("abc","abc"); 12 System.out.println("Lambda結果:" + b1); 13 14 //方法引用 15 BiPredicate<String,String> bp2 = String::equals; 16 boolean b2 = bp2.test("abc","abc"); 17 System.out.println("方法結果:" + b2); 18 } 19 20 }
執行結果
...
com.dream.test.JDK8speciality.MethodReferenceTest,test3 Lambda結果:true 方法結果:true Process finished with exit code 0
通過對象的方式引用和通過類名的方式引用不同之處是:當函數式參數列表的第一個參數是方法的調用者,而且第二個參數是被調用方法的參數的時候,我們就需要用【類名::方法名】的方式來書寫代碼。
這裡的BiPredicate也是JDK1.8的java.util.function包下的函數是介面,關於函數式介面會在後面函數式介面章節進行學習,在這裡知道它是函數介面介面即可。
2.構造器引用
由於構造器是創建對象的時候使用的所以這裡也是要用new關鍵字的。也就是【類名::new】的形式。
1 public class MethodReferenceTest { 2 //***************************** 3 // 構造器引用 類名::實例方法 4 //***************************** 5 @Test 6 public void test4(){ 7 //通過無參數的構造器創建對象 8 System.out.println("無參構造器"); 9 //Lambda表達式 10 System.out.println("Lambda表達式:"); 11 Supplier<User> su1 =() -> new User();//Lambda表達式沒有參數的時候圓括弧不可省略 12 User user1 = su1.get(); 13 System.out.println("userName:" + user1.getUserName() + " pwd:" + user1.getPwd()); 14 15 //構造器引用 16 System.out.println("構造器引用:"); 17 Supplier<User> su2 = User::new; 18 User user2 = su2.get(); 19 System.out.println("userName:" + user2.getUserName() + " pwd:" + user2.getPwd()); 20 21 //通過有參數的構造器創建對象 22 System.out.println("有參數構造器"); 23 //Lambda表達式 24 System.out.println("Lambda表達式:"); 25 BiFunction<String,String,User> bf1 = (userName,pwd) -> new User(userName,pwd); 26 User user3 = bf1.apply("[email protected]","987654321"); 27 System.out.println("userName:" + user3.getUserName() + " pwd:" + user3.getPwd()); 28 29 //構造器引用 30 System.out.println("構造器引用:"); 31 BiFunction<String,String,User> bf2 = User::new; 32 User user4 = bf2.apply("[email protected]","987654321"); 33 System.out.println("userName:" + user4.getUserName() + " pwd:" + user4.getPwd()); 34 35 /** 36 * 通過對以上有參數,無參數的構造器引用的實例可以看出: 37 * 無論構造器參數有幾個,引用部分的代碼都是ClassName::new,不同的是函數式介面。 38 */ 39 } 40 41 }
執行結果
...
com.dream.test.JDK8speciality.MethodReferenceTest,test4 無參構造器 Lambda表達式: userName:null pwd:null 構造器引用: userName:null pwd:null 有參數構造器 Lambda表達式: userName:[email protected] pwd:987654321 構造器引用: userName:[email protected] pwd:987654321 Process finished with exit code 0
有了前面幾個方法引用的瞭解這裡也就不難理解,只要記住構造方法引用的形式即可。需要註意的是:當Lambda表達式的沒有參數的時候必須寫上【() -> 】不能省略,否則報錯。
還有一個需要註意的點就是,無論構造器有幾個參數,構造器引用的形式都是【類名::構造器名】。變化的使用的函數式介面不同而已。關於函數式介面詳細會在後面函數式介面章節進行學習。
3.數組引用
數組引用的形式和構造器引用的形式類似只是變成了【類名[]::構造器名】而已。也不用做過多解釋。直接看例子即可。
1 public class MethodReferenceTest { 2 3 //***************************** 4 // 數組引用 類型::new 5 //***************************** 6 @Test 7 public void test5(){ 8 //Lambda表達式 9 Function<Integer,Integer[]> f1 =i -> new Integer[i]; 10 Integer[] iArray1 = f1.apply(10); 11 System.out.println("Lambda表達式:Array長度為" + iArray1.length); 12 13 //數組引用 14 Function<Integer,Integer[]> f2 =Integer[]::new; 15 Integer[] iArray2 = f2.apply(10); 16 System.out.println("數組引用:Array長度為" + iArray2.length); 17 } 18 19 }
執行結果
...
com.dream.test.JDK8speciality.MethodReferenceTest,test5
Lambda表達式:Array長度為10
數組引用:Array長度為10
Process finished with exit code 0
這裡使用了Function函數式介面,也會在接下來的文章中解釋。
以上就是我對於方法引用的理解,如果有理解錯誤或者寫的不好的地方還請各位大神不吝賜教呀。歡迎指正。
上一篇文章