Lambda 表達式

一、什麼是Lambda?

咱們知道,對於一個Java變量,咱們能夠賦給其一個「值」。 
這裏寫圖片描述 
若是你想把「一塊代碼」賦給一個Java變量,應該怎麼作呢? 
好比,我想把右邊那塊代碼,賦給一個叫作aBlockOfCode的Java變量: 
這裏寫圖片描述 
在Java 8以前,這個是作不到的。可是Java 8問世以後,利用Lambda特性,就能夠作到了。 
這裏寫圖片描述java

固然,這個並非一個很簡潔的寫法。因此,爲了使這個賦值操做更加elegant, 咱們能夠移除一些沒用的聲明。 
這裏寫圖片描述express

這樣,咱們就成功的很是優雅的把「一塊代碼」賦給了一個變量。而「這塊代碼」,或者說「這個被賦給一個變量的函數」,就是一個Lambda表達式。 
可是這裏仍然有一個問題,就是變量aBlockOfCode的類型應該是什麼?app

在Java 8裏面,全部的Lambda的類型都是一個接口,而Lambda表達式自己,也就是」那段代碼「,須要是這個接口的實現。這是我認爲理解Lambda的一個關鍵所在,簡而言之就是,Lambda表達式自己就是一個接口的實現。直接這樣說可能仍是有點讓人困擾,咱們繼續看看例子。咱們給上面的aBlockOfCode加上一個類型: 
這裏寫圖片描述 
這種只有一個接口函數須要被實現的接口類型,咱們叫它」函數式接口「。爲了不後來的人在這個接口中增長接口函數致使其有多個接口函數須要被實現,變成」非函數接口」,咱們能夠在這個上面加上一個聲明@FunctionalInterface, 這樣別人就沒法在裏面添加新的接口函數了: 
這裏寫圖片描述 
這樣,咱們就獲得了一個完整的Lambda表達式聲明: 
這裏寫圖片描述函數

二、Lambda表達式有什麼做用?

最直觀的做用就是使得代碼變得異常簡潔。oop

咱們能夠對比一下Lambda表達式和傳統的Java對同一個接口的實現: 
這裏寫圖片描述
這兩種寫法本質上是等價的。可是顯然,Java 8中的寫法更加優雅簡潔。而且,因爲Lambda能夠直接賦值給一個變量,咱們就能夠直接把Lambda做爲參數傳給函數, 而傳統的Java必須有明確的接口實現的定義,初始化才行: 
這裏寫圖片描述
有些狀況下,這個接口實現只須要用到一次。傳統的Java 7必需要求你定義一個「污染環境」的接口實現MyInterfaceImpl,而相較之下Java 8的Lambda, 就顯得乾淨不少。學習

Lambda結合FunctionalInterface Lib, forEach, stream(),method reference等新特性可使代碼變的更加簡潔!ui

直接上例子。3d

假設Person的定義和List<Person>的值都給定。 
這裏寫圖片描述
如今須要你打印出guiltyPersons List裏面全部LastName以」Z」開頭的人的FirstName。code

原生態Lambda寫法:定義兩個函數式接口,定義一個靜態函數,調用靜態函數並給參數賦值Lambda表達式。 
這裏寫圖片描述 
這個代碼實際上已經比較簡潔了,可是咱們還能夠更簡潔麼?orm

固然能夠。在Java 8中有一個函數式接口的包,裏面定義了大量可能用到的函數式接口(java.util.function (Java Platform SE 8 ))。因此,咱們在這裏壓根都不須要定義NameChecker和Executor這兩個函數式接口,直接用Java 8函數式接口包裏的Predicate和Consumer就能夠了——由於他們這一對的接口定義和NameChecker/Executor實際上是同樣的。 
這裏寫圖片描述 
第一步簡化 - 利用函數式接口包: 
這裏寫圖片描述
靜態函數裏面的for each循環實際上是很是礙眼的。這裏能夠利用Iterable自帶的forEach()來替代。forEach()自己能夠接受一個Consumer 參數。

第二步簡化 - 用Iterable.forEach()取代foreach loop: 
這裏寫圖片描述 
因爲靜態函數其實只是對List進行了一通操做,這裏咱們能夠甩掉靜態函數,直接使用stream()特性來完成。stream()的幾個方法都是接受Predicate,Consumer等參數的(java.util.stream (Java Platform SE 8 ))。你理解了上面的內容,stream()這裏就很是好理解了,並不須要多作解釋。

第三步簡化 - 利用stream()替代靜態函數: 
這裏寫圖片描述 
對比最開始的Lambda寫法,這裏已經很是很是簡潔了。可是若是,咱們要求變一下,變成print這我的的所有信息,及p -> System.out.println(p); 那麼還能夠利用Method reference來繼續簡化。所謂Method reference, 就是用已經寫好的別的Object/Class的method來代替Lambda expression。格式以下: 
這裏寫圖片描述

第四步簡化 - 若是是println(p),則能夠利用Method reference代替forEach中的Lambda表達式: 
這裏寫圖片描述 
這基本上就是能寫的最簡潔的版本了。

Lambda配合Optional可使Java對於null的處理變的異常優雅

這裏假設咱們有一個person object,以及一個person object的Optional wrapper: 
這裏寫圖片描述 
Optional<T>若是不結合Lambda使用的話,並不能使原來繁瑣的null check變的簡單。 
這裏寫圖片描述

只有當Optional<T>結合Lambda一塊兒使用的時候,才能發揮出其真正的威力!

咱們如今就來對比一下下面四種常見的null處理中,Java 8的Lambda+Optional<T>和傳統Java二者之間對於null的處理差別。

狀況一 - 存在則開幹 
這裏寫圖片描述
狀況二 - 存在則返回,無則返回屁 
這裏寫圖片描述
狀況三 - 存在則返回,無則由函數產生 
這裏寫圖片描述
狀況四 - 奪命連環null檢查 
這裏寫圖片描述
由上述四種狀況能夠清楚地看到,Optional<T>+Lambda可讓咱們少寫不少ifElse塊。尤爲是對於狀況四那種奪命連環null檢查,傳統java的寫法顯得冗長難懂,而新的Optional+Lambda則清新脫俗,清楚簡潔。

關於Java的Lambda, 還有東西須要討論和學習。好比如何handle lambda exception,如何利用Lambda的特性來進行parallel processing等。總之,我只是一如既往地介紹個大概,讓你大概知道,哦!原來是這樣子就OK了。網上關於Lambda有不少相關的教程,多看多練。假以時日,一定有所精益。

相關文章
相關標籤/搜索