古詩詞大全網 - 成語大全 - 為什麽要使用lambda表達式?原來如此,漲知識了

為什麽要使用lambda表達式?原來如此,漲知識了

先看幾段Java8以前經常會遇到的代碼:

創建線程並啟動

比較數組

給按鈕添加單擊事件

對於這三段代碼,我們已經司空見慣了。

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表達式後可以大幅減少冗余的模板式代碼,使把更多註意力放在業務邏輯上,而不是復制壹堆重復代碼, 除非妳在壹個用代碼行數來衡量工作量的公司,妳覺得呢?