Java 8 加入了 lambda expression 賦予了 Java 新的能力, 在使用 lambda 的同時常發現神奇的 :: 雙冒號 (double colon) 穿插其中, :: 代表什麼意義呢?
舉例來說, 在過去我們要做個由小到大的數列排序,當然使用 java.util.Arrays.sort(Object[] a) 是最快的方式, 如果要自訂排序方式使用 anonymous inner class 是最簡便的方式
例 1 : 使用 anonymous inner class
例 2 : 使用 lambda expression
例 3 : 使用 method reference
:: 雙冒號 (double colon) 是 Java 8 加入的新 operator, 稱作 Method Reference, Method Reference 提供式四個種類的用法
1. Reference to a static method
前面例3 Arrays.sort(ary, Integer::compare) 就屬此類, Integer.compare 是 static method
2. Reference to an instance method of a particular object
使用 instance method, 傳入參數與回傳型別必須與 interface 的 compare method 定義一致
使用 instance method, 與前例比較原本是傳入兩個參數 (int a, int b) 回傳一個 int, 轉換為 a.compareTo(b) 的形式, 同樣都回傳 int
Reference to a Constructor 相較其他三個比較複雜些,用下面的例子來說明,首先創建 ICarFactory interface 和 CarBean class
Java 8 可使用 lambda expression, 實作可改寫成如下的方式,簡潔許多
舉例來說, 在過去我們要做個由小到大的數列排序,當然使用 java.util.Arrays.sort(Object[] a) 是最快的方式, 如果要自訂排序方式使用 anonymous inner class 是最簡便的方式
例 1 : 使用 anonymous inner class
Integer[] ary = new Integer[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// anonymous inner class
Arrays.sort(ary, new Comparator() {
@Override
public int compare(Integer a, Integer b) {
return Integer.compare(a, b);
}
});
System.out.println(Arrays.toString(ary));
Java 8 之後你可以這樣寫例 2 : 使用 lambda expression
Integer[] ary = new Integer[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// lambda expression
Arrays.sort(ary, (a, b) -> Integer.compare(a, b));
System.out.println(Arrays.toString(ary));
是不是簡潔了很多呢? 但是我們發現 (a, b) -> Integer.compare(a, b)), 傳入兩個 Integer parameter 再 return Integer 不就跟 Integer.compare 一樣嗎? (a, b) -> 感覺好像是多餘的,因此有更精簡的做法, 就是使用 lambda expression 的 method reference例 3 : 使用 method reference
Integer[] ary = new Integer[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// method reference
Arrays.sort(ary, Integer::compare);
System.out.println(Arrays.toString(ary));
:: 雙冒號 (double colon) 是 Java 8 加入的新 operator, 稱作 Method Reference, Method Reference 提供式四個種類的用法
1. Reference to a static method
前面例3 Arrays.sort(ary, Integer::compare) 就屬此類, Integer.compare 是 static method
2. Reference to an instance method of a particular object
使用 instance method, 傳入參數與回傳型別必須與 interface 的 compare method 定義一致
class MyCompare {
public int compareInt(int a, int b) {
return a - b;
}
}
Integer[] ary = new Integer[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
MyCompare my = new MyCompare();
Arrays.sort(ary, my::compareInt);
System.out.println(Arrays.toString(ary));
3. Reference to an instance method of an arbitrary object of a particular type使用 instance method, 與前例比較原本是傳入兩個參數 (int a, int b) 回傳一個 int, 轉換為 a.compareTo(b) 的形式, 同樣都回傳 int
Integer[] ary = new Integer[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
Arrays.sort(ary, Integer::compareTo);
System.out.println(Arrays.toString(ary));
4. Reference to a ConstructorReference to a Constructor 相較其他三個比較複雜些,用下面的例子來說明,首先創建 ICarFactory interface 和 CarBean class
interface ICarFactory {
CarBean getCar(String color, int year);
}
class CarBean {
private String name;
private int maxSpeed;
CarBean(String name, int maxSpeed) {
this.name = name;
this.maxSpeed = maxSpeed;
}
String getName() {
return name;
}
int getMaxSpeed() {
return maxSpeed;
}
}
要實作 ICarFactory, 傳統的方法是使用 "implements" 關鍵字來實作介面Java 8 可使用 lambda expression, 實作可改寫成如下的方式,簡潔許多
ICarFactory f = (String name, int maxSpeed) -> { return new CarBean(name, maxSpeed); };
仔細觀察可發現,Interface 所定義的 getCar(String color, int year) 和 CarBean(String name, int maxSpeed) 傳入參數型別正好一樣,因此可使用 method reference => Reference to a Constructor 的方式,再把寫法簡化ICarFactory f = CarBean::new;測試 Reference to a Constructor
//ICarFactory f = (String name, int maxSpeed) -> { return new CarBean(name, maxSpeed); };
ICarFactory f = CarBean::new;
CarBean c = f.getCar("GTR", 300);
System.out.println("Car Name:" + c.getName() + " / Max Speed:" + c.getMaxSpeed());
使用 lambda 或 method reference 可有效的讓程式碼更簡短,也提供程式更大的彈性,不管用以上哪一種寫法都是由編譯器來做推斷和解釋完成,這是使用上需要留意的部分