創建線程並啟動
比較數組
給按鈕添加單擊事件
對於這三段代碼,我們已經司空見慣了。
Java復雜冗余的代碼實現壹直被程序員所詬病,好在隨著JVM平臺語言Scala的興起以及函數式編程風格的風靡,讓Oracle在Java的第8個系列版本中進行了革命性的變化,推出了壹系列函數式編程風格的語法特性,比如Lambda表達式以及Stream。
如果采用Lambda表達式,上面三段代碼的實現將會變得極為簡潔。
創建線程並啟動(采用Lambda版本)
比較數組(采用Lambda版本)
給按鈕添加單擊事件(采用Lambda版本)
格式:(參數) -> 表達式
其中:
壹個參數
多個參數
0個參數
表達式塊
在Java8中新增加了壹個註解: [@FunctionalInterface],函數式接口。
什麽是函數式接口呢?它包含了以下特征:
Lambda表達式的本質就是函數式接口的匿名實現。只是把原有的接口實現方式用壹種更像函數式編程的語法表示出來。
Java8的java.util.function包已經內置了大量的函數式接口,如下所示:
從中可以看出:
以下是壹個綜合的例子:
如果覺得這些內置函數式接口還不夠用的話,還可以自定義自己的函數式接口,以滿足更多的需求。
如果Lambda表達式已經有實現的方法了,則可以用方法引用進行簡化。 方法引用的語法如下:
這樣前面提到的Lambda表達式:
則可以替換為:
另壹個例子:
可以替換為:
註意:方法名後面是不能帶參數的! 可以寫成System.out::println,但不能寫成System.out::println(“hello”)
如果能獲取到本實例的this參數,則可以直接用this::實例方法進行訪問,對於父類指定方法,用super::實例方法進行訪問。
下面是壹個例子:
構造器引用和方法引用類似,只不過函數接口返回實例對象或者數組。 構造器引用的語法如下:
舉個例子:
其中的labels.stream().map(Button::new)相當於 labels.stream().map(label->new Button(label))
再看個數組類型的構造器引用的例子:
把Stream直接轉成了數組類型,這裏用Button[]::new來標示數組類型。
先看壹段代碼:
壹個lambda表達式壹般由以下三部分組成:
參數和表達式好理解。那自由變量是什麽呢? 它就是在lambda表達式中引用的外部變量,比如上例中的text和count變量。
如果熟悉函數式編程的同學會發現,Lambda表達式其實就是”閉包”(closure)。只是Java8並未叫這個名字。 對於自由變量,如果Lambda表達式需要引用,是不允許發生修改的。
比如下面的代碼:
先說說為什麽要在Java8接口中新增默認方法吧。
比如Collection接口的設計人員針對集合的遍歷新增加了壹個forEach()方法,用它可以更簡潔的遍歷集合。 比如:
但如果在接口中新增方法,按照傳統的方法,Collection接口的自定義實現類都要實現forEach()方法,這對廣大已有實現來說是無法接受的。
於是Java8的設計人員就想出了這個辦法:在接口中新增加壹個方法類型,叫默認方法,可以提供默認的方法實現,這樣實現類如果不實現方法的話,可以默認使用默認方法中的實現。
壹個使用例子:
默認方法的加入,可以替代之前經典的接口和抽象類的設計方式,統壹把抽象方法和默認實現都放在壹個接口中定義。這估計也是從Scala的Trait偷師來的技能吧。
除了默認方法,Java8還支持在接口中定義靜態方法以及實現。
比如Java8之前,對於Path接口,壹般都會定義壹個Paths的工具類,通過靜態方法實現接口的輔助方法。
接口中有了靜態方法就好辦了, 統壹在壹個接口中搞定!雖然這看上去破壞了接口原有的設計思想。
這樣Paths類就沒什麽意義了~
使用Lambda表達式後可以大幅減少冗余的模板式代碼,使把更多註意力放在業務邏輯上,而不是復制壹堆重復代碼, 除非妳在壹個用代碼行數來衡量工作量的公司,妳覺得呢?