讀書筆記,《Java 8實戰》,第三章,Lambda表達式

第一節,Lambda管中窺豹
   能夠把Lambda表達式理解爲簡潔地表示可傳遞的匿名函數的一種方式,它沒有名稱,但它有參數列表、函數主題和返回值。
   本節介紹了Lambda表達式的語法,它包括參數列表、箭頭、Lambda的主體,其中Lambda主體能夠包括多行,這個時候必須用大括號把它括起來。
   本節的最後做者給出了Lambda語法的幾個例子,讓咱們來辨別什麼是合法的Lambda表達式語法,其中在沒有大括號的時候用return是不對的,帶有大括號的時候用單行的表達式也是不對的。
 
第二節,在哪裏以及如何使用Lambda
   咱們能夠在函數式接口上使用Lambda表達式,那麼本節中做者也提出了什麼是函數式接口?函數式接口就是隻有一個抽象方法的接口,好比傳統Java裏面的Comparator, Runnable, EventListener,Callable, PrivilegedAction。
   而後這裏做者又提出了默認方法的概念。所謂的默認方法就是在類沒有對接口方法進行實現的時候,在接口主體也爲方法提供了默認實現的方法,哪怕有不少默然方法,只要接口只有一個抽象方法,那它就仍然是一個函數式接口。
   做者在這裏給了幾個讓咱們辨認什麼是函數式接口的例子,有兩個錯誤的例子,一個是裏面一個藉口都沒有定義的,另一個裏面雖然自定義一個接口,可是他還從父接口中繼承了一個抽象接口。
   函數式接口的抽象方法的簽名,基本上就是Lambda表達式的簽名,咱們將這種抽象方法叫作函數描述符。好比Runnnable接口能夠看作一個什麼也不接受,什麼也不返回的函數的簽名。
   關於能夠在哪裏使用Lambda,其實有不少,好比能夠做爲函數的入參、做爲函數的返回值、又或者把它賦值給一個局部變量。後做者提到了一個叫作@FunctionalInterface的註解
 
第三節,把Lambda付諸實踐,環繞執行模式。
   所謂的環繞執行模式其實就相似於之前咱們學到的模版方法模式,這裏使用的是try...catch的例子。固然在模板方法中,咱們通常是經過在子類重寫抽象方法的形式來讓模板方法具備不一樣的行爲,在本節中,咱們能夠經過表達式的方式直接把代碼傳遞給方法,從而實現不一樣的行爲。
 
第四節,使用函數式接口
   函數式接口頗有用,由於抽象方法的簽名能夠描述Lambda表達式的簽名,函數式接口的抽象方法的簽名稱爲函數描述符,因此爲了運用不一樣的表達式,你須要一套可以描述常見描述函數描述符的函數式藉口。在Java的API中已經有了幾個函數式的接口。好比Comparable, Runnable ,Callable, 在Java8中,設計師在java.util.funtion包又添加了幾個新的函數是接口,好比Predicate ,Consumer ,Funtion。
   而後做者又提到了這種函數式接口對於基本類型的特化,爲何要特化呢,由於對於原始類型的裝箱和拆箱性能比較低。有了特化以後就能夠避免這種裝箱拆箱的操做。
   而後再在p46頁中給出了一個表格,其中列出了在Java8中的經常使用的函數式接口。主要就是斷言、消費者、函數,以及它們的單參數、多參數、基本類型特化的各類變體。
   在這裏做者提到了任意函數式接口都不容許拋出受檢異常,若是你須要Lambda表達式來拋出異常,有兩種方法:第一種是定義一個本身的函數是接口,並申明受檢異常;第二,把Lambda包在一個try catch塊中。
 
第五節,類型檢查,類型推斷以及限制
   Lambda的類型是從使用Lambda的上下文中推斷出來的。上下文中Lambda表達式須要的類型稱爲目標類型有了目標類型的概念,那麼同一個Lambda表達式就能夠與不一樣的函數式接口聯繫起來,只要他們的抽象方法簽名可以兼容就行。你們可能還記得在Java7中就已經引入的菱形運算符,利用泛型推斷從上下文中推斷類型的思想。
   這裏還有一個特殊的void 的兼容規則, 也就是說,若是一個Lambda的主體是一個語句表達式,他就和一個返回void 的函數描述符兼容。
   第四小節,使用局部變量
   咱們迄今爲止所介紹的全部Lambda表達式都只用到了其主體裏面的參數,可是人們仍是也容許使用自由變量,就像匿名類同樣。所謂自由變量,就是在外層做用域中定義的變量雖然它可使用自由變量,但實際上是有一些限制的。Lambda能夠沒有限制的使用實例變量和靜態變量,可是局部變量必須顯示的聲明爲final。換句話說就是lambda表達式,只能捕獲指派給他們的局部變量一次之因此會有這種限制,是由於局部變量是分配在棧上的,而實例變量和靜態變量是分配在堆棧的。基於java中對於自由變量的這種限制,因此它實際上不具備JS中的那種閉包的概念。
 
第六節,方法引用
   方法應用能夠被看做僅僅調用特定方法的Lambda的一種快捷寫法,它的基本思想是,若是Lambda表明的只是直接調用這個方法,那最好仍是用名稱來調用它,而不是去描述如何調用它。由於顯示的指定方法的名稱,你的代碼的可讀性會更好。
 
   在這裏,做者給出了,三種類型的方法引用:
   第一種,指向靜態方法的方法應用,好比integer的parseInt方法。
   第二種,只想問你類型實例方法的方法已有,好比String的 length方法。
   第三種,指向現有對象的實例方法的方法應用,這個所謂的現有對象,不是表達式的入參,而是上文提到的那種自由變量,用就是外層做用域中的變量。
   第二小節,構造函數引用
   也就是說對於一個現有的構造函數,你能夠利用它的名稱和關鍵字new,來建立它的一個引用,像這樣Classname::new 可是這個方法應用建立好以後賦值給誰就有點講究了,這主要是根據這個構造函數的參數的多少而有所不一樣,好比說沒有參數、一個參數、兩個參數等等,分別能夠給Supplier, Function ,BiFunction,。
   構造函數應用的一個典型應用就是用來構造簡單工廠方法,直接把每個類的構造函數註冊到工廠的字典裏面去。
 
第七節,lambda和方法應用實戰
   這一節惟一要注意的就是Comparator的那個看comparing 靜態輔助方法。他能夠接受一個function來提取comparable鍵值 ,並生成一個Comparator 對象,他的實現代碼以下:
 public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); }

 

 
第八節,複合Lambda 表達式的有用方法
   這一節主要列出了Java8新提供的幾個函數式接口:Comparator, Function, Predicate新提供的默認方法來做爲複合方法。有了複合方法以後,就意味着你能夠把多個簡單的Lambda複合成複雜的表達式。好比你可讓兩個謂詞作一個or操做,組合成一個更大的謂詞,並且你還可讓一個函數的結果成爲另外一個函數的輸入,你可能會想函數式接口怎麼可能有更多的方法呢?竅門在於咱們即將介紹的方法都是默認方法,也就是說它們不是抽象方法。而後做者詳細地給出了,比較器複合,謂詞複合 、函數複合。具體都包含哪些複合函數就要本身去看了。這些複合函數組合起來還確實是挺神奇的。
相關文章
相關標籤/搜索