[Java] 17.4. 方法引用

方法引用,透過方法引用,你可以將已經存在、開發好的方法變成lambda當作運算式使用。

 

image/svg+xml17.4. ⽅法引⽤ - Method References import java.util.*; public class EmployeeFind { public boolean isMore20Age ( Employee emp){ return emp.age >= 20 ; } public boolean isJackOrMary ( Employee emp){ return emp.name == "Jack" || emp.name == "Mary" ; } } public interface Filter < T >{ boolean keep ( T item ); } import java.util.*; public class EmployeeFind { public boolean isMore20Age ( Employee emp){ return emp.age >= 20 ; } public boolean isJackOrMary ( Employee emp){ return emp.name == "Jack" || emp.name == "Mary" ; } } import java.util.*; class Main{ public static void main( String [] args){ Employee e1 = new Employee ( "K12345678" , “Jack" , 20 , " 男⽣ " , "048679" , 40000 ); Employee e2 = new Employee ( "K00000000" , “Eric" , 25 , " 男⽣ " , "041121" , 45000 ); Employee e3 = new Employee ( "K11111111" , “Mary" , 18 , " 女⽣ " , "050021" , 30000 ); Employee e4 = new Employee ( "K22222222" , “Jack" , 19 , " 男⽣ " , "051212" , 42000 ); List < Employee > l = new ArrayList < Employee >(); l.add(e1); l.add(e2); l.add(e3); l.add(e4); EmployeeFind find = new EmployeeFind (); List < Employee > result1 = Collection.filter(l, find :: isMore20Age ); for ( Employee emp : result1){ System.out.println(emp.age); } List < Employee > result2 = Collection.filter(l, find :: isJackOrMary ); for ( Employee emp : result2){ System.out.println(emp.name); } } } import java.util.*; class Main{ public static void main( String [] args){ Employee e1 = new Employee ( "K12345678" , “Jack" , 20 , " 男⽣ " , "048679" , 40000 ); Employee e2 = new Employee ( "K00000000" , “Eric" , 25 , " 男⽣ " , "041121" , 45000 ); Employee e3 = new Employee ( "K11111111" , “Mary" , 18 , " 女⽣ " , "050021" , 30000 ); Employee e4 = new Employee ( "K22222222" , “Jack" , 19 , " 男⽣ " , "051212" , 42000 ); List < Employee > l = new ArrayList < Employee >(); l.add(e1); l.add(e2); l.add(e3); l.add(e4); EmployeeFind find = new EmployeeFind (); Filter < Employee > obj = find :: isMore20Age ; List < Employee > result1 = Collection.filter (l, find :: isMore20Age ); } } public class EmployeeFind { public boolean isMore20Age ( Employee emp){ return emp.age >= 20 ; } public static boolean isJackOrMary ( Employee emp){ return emp.name == "Jack" || emp.name == "Mary" ; } } import java.util.*; class Main{ public static void main( String [] args){ Employee e1 = new Employee ( "K12345678" , “Jack" , 20 , " 男⽣ " , "048679" , 40000 ); Employee e2 = new Employee ( "K00000000" , “Eric" , 25 , " 男⽣ " , "041121" , 45000 ); Employee e3 = new Employee ( "K11111111" , “Mary" , 18 , " 女⽣ " , "050021" , 30000 ); Employee e4 = new Employee ( "K22222222" , “Jack" , 19 , " 男⽣ " , "051212" , 42000 ); List < Employee > l = new ArrayList < Employee >(); l.add(e1); l.add(e2); l.add(e3); l.add(e4); EmployeeFind find = new EmployeeFind (); List < Employee > result1 = Collection.filter(l, find :: isMore20Age ); for ( Employee emp : result1){ System.out.println(emp.age); } List < Employee > result2 = Collection.filter(l, EmployeeFind::isJackOrMary ); for ( Employee emp : result2){ System.out.println(emp.name); } } } import java.util.*; class Main{ public static void main( String [] args){ Employee e1 = new Employee ( "K12345678" , “Jack" , 20 , " 男⽣ " , "048679" , 40000 ); Employee e2 = new Employee ( "K00000000" , “Eric" , 25 , " 男⽣ " , "041121" , 45000 ); Employee e3 = new Employee ( "K11111111" , “Mary" , 18 , " 女⽣ " , "050021" , 30000 ); Employee e4 = new Employee ( "K22222222" , “Jack" , 19 , " 男⽣ " , "051212" , 42000 ); List < Employee > l = new ArrayList < Employee >(); l.add(e1); l.add(e2); l.add(e3); l.add(e4); List < Employee > result1 = Collection.filter(l, emp -> emp.age >= 20 ); for ( Employee emp : result1){ System.out.println(emp.age); } List < Employee > result2 = Collection.filter(l, EmployeeFind :: isJackOrMary ); for ( Employee emp : result2){ System.out.println(emp.name); } } } J17_4_1 EmployeeFind.java 1. 製作⼀個員⼯查詢類別 - EmployeeFind ,裡⾯放了兩個已經 寫好的⽅法,⽤來判斷是否⼤於等於 20 歲,與是否為 Jack Mary J17_4_2 Main.java 2. 這些⽅法的格式也與過瀘函式介⾯的 Keep() ⽅法格式符 合,有⼀個參數與⼀個布林回傳值。這些寫好的⽅法可以像 lambda 簡單,直接⽤來過瀘員⼯嗎 ? J17_4_1 Filter.java J17_4_2 EmployeeFind.java 1. 製作⼀個員⼯查詢類別 - EmployeeFind ,裡⾯放了兩個已經寫 好的⽅法,⽤來判斷是否⼤於等於 20 歲,與是否為 Jack Mary 2. 建立員⼯查詢物件。 3. 透過雙冒號 (::) 的⽅式直接引⽤員⼯查詢物件的 isMore20Age 法,注意,這裡的⽅法是帶入參考⽤的,後⾯沒有呼叫的⼩括號 (()) 4. 透過 :: 參考的⽅式,就如同使⽤ lambda 樣,會建立⼀個過瀘函式介⾯的匿名類別的物件。 5. 其中的 isMore20Age ⽅法也符合過瀘函式介⾯上的 keep() ⽅法的格式,參數 的型別也透過推論⼀致得到 Employee ,因此可以實作這個匿名類別,如此我們就 達到應⽤即有的⽅法來實現如同 lambda 般透過編譯器⾃動實作匿名類別的功能。 6. 再次使⽤雙冒號 (::) 引⽤員⼯查詢物件下的 isJackOrMary ⽅法,來以找出 Jack Mary ,⼀樣不加上⼩括號 (()) J17_4_3 Main.java 1. 建立員⼯查詢物件。 2. 實際上 :: ⽅法引⽤在編譯時也會被實作成匿名類別然後建立此類別的物件。 3. 在此宣告⼀個 Filter<Employee> 型別的變數 obj ,編譯器從此變數的型別得 知要實作的⽅法是 Filter 上的 keep() ⽅法且格式與 isMore20Age() ⽅法的格式 相符,最後編譯器就會建立 Filter 型別的匿名類別的物件,在放入 obj 數中。 4. 同理,帶入 Collection.filter() ⽅法中的 :: ⽅法引⽤也是如此, 最後都會被編譯器實作為 Filter 型別的匿名類別的物件後帶入參數中。 J17_4_4 EmployeeFind.java J17_4_4 Main.java 1. 這是員⼯查詢類別 - EmployeeFind ,現在我們將 isJackOrMary() ⽅法加上 static 靜態化, isMore20Age() ⽅法唯持不變。 2. 建立員⼯查詢物件於 find 變數中,然後透過 find 變數 中的物件使⽤⽅法引⽤ find::isMore20Age ,沒問題。 3. isJackOrMary() 是⼀個加上 static 靜態化的⽅法,使⽤類別直接 進⾏⽅法引⽤ EmployeeFind::isJackOrMary ,這也沒問題,只要⽅ 法的格式符合 Filter 函式介⾯的 keep() ⽅法,都可以進⾏引⽤。 J17_4_5 Main.java 1. 無論是使⽤ lambda 或雙冒號 (::) ⽅法引⽤,最後編譯器 都會建立對應函式介⾯的匿名類別,並建立其物件。 2. lambda 會將箭頭 (->) 後⽅的程式作為實作 ⽅法的程式,即實作 keep() ⽅法中的程式。 3. 雙冒號 (::) ⽅法引⽤與 lambda 不同的是這個參考的⽅法其實就是⽅ 法實作的內容,它會在實作中的⽅法中被呼叫,在此的範例即是在 keep() ⽅法中轉呼叫引⽤ isJackOrMary ⽅法。 這些存在於篩選員⼯類別上的篩選⽅法, 也可以使⽤ lambda ? :: ⽅法引⽤,引⽤即有的篩選函式 實際上 :: ⽅法引⽤也會實作匿名類別 靜態⽅法、物件⽅法,只要格式符合都可引⽤ lambda vs :: ⽅法引⽤

留言