參考書籍:《Java 8函數式編程》
Java8帶來最大的改變就是Lambda表達式了,廢話不多說,開始正題~
定義:Lambda表達式是一個匿名方法,將行為像數據一樣傳遞。
以前我們的習慣都是傳遞基本類型和對象類型的數據,現在可以傳遞行為了~常見結構:
BinaryOperator<Integer> add = (x, y) -> x + y;
本來是這樣寫的BinaryOperator<Integer> add = (Integer x, Integer y) -> x + y;
但因為類型推斷,編譯器會根據前面的泛型<Integer>自動推斷出后面的參數類型,所以可以簡寫成上面的樣子。
如果只有一個參數的Lambda表達式,括號都可以省略,直接寫成x->x>5
;
根據參數個數和返回值的不同,Java8中都有對應的函數式接口。具體的接口有哪些暫時不談。
事實上Java7中就已經存在了類型推斷,比如定義一個List<Integer> list = new ArrayList<>();
右邊無需再寫類型。方法引用的關鍵字
::
,用來傳遞方法或者構造函數引用。
比如上面的表達式可以寫為:BinaryOperator<Integer> add = Integer::sum;
引用構造方法就可以寫成Class::new
函數式接口:僅僅只有一個抽象方法的接口,類上有注解
@FunctionalInterface
標示。
接收Lambda表達式的類全部都是函數式接口。上面的BinaryOperator
就是如此。
事實上是可以有多個抽象方法,只不過其他抽象方法必須是Object類中的public方法,比如equals方法。因為接口都有實現類,而類都繼承Object,最終都有equals方法,只不過接口中定義equals方法,會強制你實現equals方法罷了~
另外除了抽象方法,還可以有靜態方法,默認方法(Java8新增的關鍵字default
),所以接口再也不是只有抽象方法了。
新增默認方法,只是為了向后兼容,比如List接口中新增抽象方法,所有的實現類都要去實現它,太麻煩。而定義默認方法,子類就都繼承了該方法,無需太多改動。那如果子類已經有該同名方法了,Java會如何調用呢?答案是優先調用子類方法。
public interface Function {
default String get() {
return "Function";
}
}
public class FuncitonImpl implements Function {
public static void main(String[] args) {
Function fun = new FuncitonImpl();
System.out.println(fun.get());
}
public String get() {
return "FuncitonImpl";
}
}
輸出結果:FuncitonImpl
-
高階函數:方法參數為一個函數或者返回值為一個函數
方法重載時,如果一個方法參數為函數式接口,而另一個方法參數為其子類,那么調用方法時,會調用參數為子類的方法。
public interface IntegerBiFunciton extends BinaryOperator<Integer> {
}
public static void get(IntegerBiFunciton function ) {
System.out.println("IntegerBiFunciton function...");
}
public static void get(BinaryOperator<Integer> function ) {
System.out.println("BinaryOperator function...");
}
調用get方法時,輸出結果:IntegerBiFunciton function...