函數(shù)式編程
定義
函數(shù)式編程(funcational programming)屬于結(jié)構(gòu)化編程的一種。主要思想是把運(yùn)算過程盡量寫成一系列嵌套的函數(shù)調(diào)用。
結(jié)構(gòu)化編程
一種編程范型,采用子程序、代碼區(qū)塊、for循環(huán)以及while循環(huán) 等結(jié)構(gòu)來取代傳統(tǒng)的goto。
函數(shù)式編程關(guān)心數(shù)據(jù)的映射,命令式編程關(guān)心解決問題的步驟。
特點(diǎn)
函數(shù)是“第一等公民”
函數(shù)和其他數(shù)據(jù)類型一樣,可以賦值給其他變量,作為其他函數(shù)的傳入?yún)?shù)或返回值。只用“表達(dá)式”,不用“語句”
“expression” 是一個(gè)單純的運(yùn)算過程,總是有返回值?!皊tatement”是執(zhí)行某種操作,沒有返回值。沒有“副作用”
“副作用”是指函數(shù)內(nèi)部有與外部的互動(dòng),產(chǎn)生運(yùn)算以外的其他結(jié)果。函數(shù)要保持獨(dú)立,所有功能返回一個(gè)新的值,尤其不得修改外部變量的值。
純函數(shù)是這樣一種函數(shù),即相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出,而且沒有任何可觀察的副作用。
不修改狀態(tài)
函數(shù)式編程使用參數(shù)保存狀態(tài),只返回新的值,不修改系統(tǒng)變量。引用透明(Referential transparency)
函數(shù)的運(yùn)行不依賴外部變量或“狀態(tài)”,只依賴輸入?yún)?shù)。只要參數(shù)相同,引用函數(shù)返回值總是相同的。
構(gòu)成
高階函數(shù)(higher-order function)
能夠接受一個(gè)函數(shù)作為參數(shù)的函數(shù)。函子(Functor)
函子是函數(shù)式編程里最重要的數(shù)據(jù)類型,也是基本的運(yùn)算單位和功能單位。
函子是指具有map方法的容器,包含了值和變形關(guān)系。map方法將容器里面的每一個(gè)值,映射到另一個(gè)容器。即將一個(gè)范疇轉(zhuǎn)換成令一個(gè)范疇。
構(gòu)成
范疇這種數(shù)據(jù)模型的要素:
所有成員是一個(gè)集合
變形關(guān)系是函數(shù)
- 閉包(Closure)
閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),可簡(jiǎn)單理解成"定義在一個(gè)函數(shù)內(nèi)部的函數(shù)"。當(dāng)內(nèi)嵌函數(shù)體內(nèi)引用到體外的變量時(shí),將會(huì)把定義時(shí)涉及到的引用環(huán)境和函數(shù)體打包成一個(gè)整體(閉包)返回。
類是有行為的數(shù)據(jù),閉包是有數(shù)據(jù)的行為。
閉包是由函數(shù)及其相關(guān)的引用環(huán)境組合而成的實(shí)體,即閉包=函數(shù)+引用環(huán)境。
參考
函數(shù)式編程入門教程
函數(shù)式編程初探
學(xué)習(xí)Javascript閉包(Closure)
lambda
lambda表達(dá)式通常在需要一個(gè)函數(shù),但是又不想費(fèi)神去命名一個(gè)函數(shù)的場(chǎng)合下使用,也就是指匿名函數(shù)。參考
Lambda表達(dá)式的本質(zhì)只是一個(gè)"語法糖",由編譯器推斷并幫你轉(zhuǎn)換包裝為常規(guī)的代碼,因此你可以使用更少的代碼來實(shí)現(xiàn)同樣的功能。
JAVA中的lambda
Java8之前,傳遞行為的唯一方法就是通過匿名內(nèi)部類。Java中的lamda不是一個(gè)匿名內(nèi)部類的語法糖。在匿名類中,this指代的是匿名類本身;而在lambda表達(dá)式中,this指代的是lambda表達(dá)式所在的這個(gè)類。
1.lambda表達(dá)式
只有那些僅僅包含一個(gè)非實(shí)例化抽象方法的接口才能使用lambda表達(dá)式。Runnable接口就是函數(shù)式接口的一個(gè)例子。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Java8默認(rèn)帶有許多可以直接在代碼中使用的函數(shù)式接口,它們位于java.util.function包中。
2.lambda表達(dá)式結(jié)構(gòu)
-> 是用來把參數(shù)從函數(shù)體中分離出來的操作符。
在lambda表達(dá)式中,我們不需要明確指出參數(shù)類型,javac編譯器會(huì)通過上下文自動(dòng)推斷參數(shù)的類型信息。根據(jù)上下文推斷類型的行為稱為類型推斷。
3.方法引用
當(dāng)需要為一個(gè)特定方法創(chuàng)建lambda表達(dá)式,比如Function<String, Integer> strToLength = String::length;,可以用縮寫符號(hào)表示。String是目標(biāo)引用,::是定界符,length是目標(biāo)引用的方法。該方法可以是靜態(tài)或者實(shí)例方法。
參考原文
4.實(shí)現(xiàn)機(jī)制
采用在Java7中新增的動(dòng)態(tài)啟用來延遲在運(yùn)行時(shí)的加載策略。當(dāng)javac編譯代碼時(shí),捕獲代碼中的lambda表達(dá)式并生成一個(gè)動(dòng)態(tài)啟用的調(diào)用地址(稱lambda工廠)。當(dāng)動(dòng)態(tài)啟用被調(diào)用時(shí),就會(huì)向lambda表達(dá)式發(fā)生轉(zhuǎn)換的地方返回一個(gè)函數(shù)式接口的實(shí)例。
JAVA中的Stream
Stream是Java 8 提供的高效操作集合類(Collection)數(shù)據(jù)的API。Stream使用一種類似用SQL語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對(duì)JAVA集合運(yùn)算和表達(dá)的高階抽象。
-
與
Collection對(duì)比
Java8運(yùn)行開發(fā)者使用stream方法基于Collection集合創(chuàng)建一個(gè)Stream管道。Stream采用內(nèi)部迭代。
Collection與Stream處理集合方式的不同:
Collection與Stream處理集合方式的不同 懶加載
Stream不會(huì)儲(chǔ)存數(shù)據(jù),懶加載(只有在被使用到時(shí)才會(huì)執(zhí)行計(jì)算)。Stream表達(dá)式在被末端操作方法調(diào)用之前不會(huì)被賦值計(jì)算。
-
過渡操作:從已存在的stream上產(chǎn)生另一個(gè)新的stream的函數(shù),比如filter,map,sorted等 -
末端操作:從stream上產(chǎn)生一個(gè)非stream結(jié)果的函數(shù),比如collect(toList()),forEach,count,get等