java8中函數(shù)式編程的示例分析

這篇文章主要介紹了java8中函數(shù)式編程的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、皋蘭網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

函數(shù)式編程語言是什么?

函數(shù)式編程語言的核心是它以處理數(shù)據(jù)的方式處理代碼。這意味著函數(shù)應(yīng)該是第一等級(jí)(First-class)的值,并且能夠被賦值給變量,傳遞給函數(shù)等等。

事實(shí)上,很多函數(shù)式語言比這走得更遠(yuǎn),將計(jì)算和算法看得比它們操作的數(shù)據(jù)更重要。其中有些語言想分離程序狀態(tài)和函數(shù)(以一種看起來有點(diǎn)對(duì)立的方式,使用面向?qū)ο蟮恼Z言,這通常會(huì)將它們聯(lián)系得更緊密)。

Clojure編程語言就是一個(gè)這樣的例子,盡管它運(yùn)行于基于類的Java虛擬機(jī),Clojure的本質(zhì)是函數(shù)式語言,并且在高級(jí)語言源程序中不直接公布類和對(duì)象(盡管提供了與Java良好的互操作性)。

下面顯示的是一個(gè)Clojure函數(shù),用于處理日志,是一等公民(First-class citizen),并且不需要綁定一個(gè)類而存在。

(defn build-map-http-entries [log-file]
(group-by :uri (scan-log-for-http-entries log-file)))

當(dāng)寫在函數(shù)中的程序,對(duì)給定的輸入(不論程序中的其它狀態(tài)如何)總是返回相同的輸出,并且不會(huì)產(chǎn)生其它影響,或者改變?nèi)魏纬绦驙顟B(tài),這時(shí)候函數(shù)式編程是最有用的。它們的行為與數(shù)學(xué)函數(shù)相同,有時(shí)候把遵循這個(gè)標(biāo)準(zhǔn)的函數(shù)稱為“純”函數(shù)。

純函數(shù)的巨大好處是它們更容易推論,因?yàn)樗鼈兊牟僮鞑灰蕾囉谕獠繝顟B(tài)。函數(shù)能夠很容易地結(jié)合在一起,這在開發(fā)者工作流風(fēng)格中很常見,例如Lisp方言和其它具有強(qiáng)函數(shù)傳統(tǒng)的語言中很普遍的REPL(Read, Execute, Print, Loop)風(fēng)格。

非函數(shù)式編程語言中的函數(shù)式編程

一種語言是不是函數(shù)式并不是非此即彼的狀態(tài),實(shí)際上,語言存在于圖譜上。在最末端,基本上是強(qiáng)制函數(shù)式編程,通常禁止可變的數(shù)據(jù)結(jié)構(gòu)。Clojure就是一種不接受可變數(shù)據(jù)的語言。

不過,也有一些其它語言,通常以函數(shù)方式編程,但語言并不強(qiáng)制這一點(diǎn)。Scala就是一個(gè)例子,它混和了面向?qū)ο蠛秃瘮?shù)式語言。允許函數(shù)作為值,例如:

val sqFn = (x: Int) => x * x

同時(shí)保留與Java非常接近的類和對(duì)象語法。

另一個(gè)極端,當(dāng)然,使用完全非函數(shù)式語言進(jìn)行函數(shù)式編程是可能的,例如C語言,只要維持好合適的程序員準(zhǔn)則和慣例。

考慮到這一點(diǎn),函數(shù)式編程應(yīng)該被看作是有兩個(gè)因素的函數(shù),其中一個(gè)與編程語言相關(guān),另一個(gè)是用該語言編寫的程序:

1)底層編程語言在多大程度上支持,或者強(qiáng)制函數(shù)式編程?

2)這個(gè)特定的程序如何使用語言提供的函數(shù)式特性?它是否避免了非函數(shù)式特性,例如可變狀態(tài)?

Java的一些歷史

Java是一種固執(zhí)己見的語言,它具有很好的可讀性,初級(jí)程序員很容易上手,具有長期穩(wěn)定性和可支持性。但這些設(shè)計(jì)決定也付出了一定的代價(jià):冗長的代碼,類型系統(tǒng)與其它語言相比顯得缺乏彈性。

然而,Java的類型系統(tǒng)已經(jīng)在演化,雖然在語言的歷史當(dāng)中相對(duì)比較慢。我們來看看這些年來它的一些形式。

Java最初的類型系統(tǒng)

Java最初的類型系統(tǒng)至今已經(jīng)超過15年了。它簡(jiǎn)單而清晰,類型包括引用類型和基本類型。類、接口或者數(shù)組屬于引用類型。

類是Java平臺(tái)的核心,類是Java平臺(tái)將會(huì)加載、或鏈接的功能的基本單位,所有要執(zhí)行的代碼都必須駐留于一個(gè)類中。

接口不能直接實(shí)例化,而是要通過一個(gè)實(shí)現(xiàn)了接口API的類。

數(shù)組可以包含基本類型、類的實(shí)例或者其它數(shù)組。

基本類型全部由平臺(tái)定義,程序員不能定義新的基本類型。

從最早開始,Java的類型系統(tǒng)一直堅(jiān)持很重要的一點(diǎn),每一種類型都必須有一個(gè)可以被引用的名字。這被稱為“標(biāo)明類型(Nominative typing)”,Java是一種強(qiáng)標(biāo)明類型語言。

即使是所謂的“匿名內(nèi)部類”也仍然有類型,程序員必須能引用它們,才能實(shí)現(xiàn)那些接口類型:

Runnable r = new Runnable() { public void run() { System.out.println("Hello World!"); } };

換種說法,Java中的每個(gè)值要么是基本類型,要么是某個(gè)類的實(shí)例。

命名類型(Named Type)的其它選擇

其它語言沒有這么迷戀命名類型。例如,Java沒有這樣的Scala概念,一個(gè)實(shí)現(xiàn)(特定簽名的)特定方法的類型。在Scala中,可以這樣寫:

x : {def bar : String}

記住,Scala在右側(cè)標(biāo)示變量類型(冒號(hào)后面),所以這讀起來像是“x是一種類型,它有一個(gè)方法bar返回String”。我們能用它來定義類似這樣的Scala方法:

def showRefine(x : {def bar : String}) = { print(x.bar) }

然后,如果我們定義一個(gè)合適的Scala對(duì)象:

object barBell { def bar = "Bell" }

然后調(diào)用showRefine(barBell),這就是我們期待的事:

showRefine(barBell) Bell

這是一個(gè)精化類型(Refinement typing)的例子。從動(dòng)態(tài)語言轉(zhuǎn)過來的程序員可能熟悉“鴨子類型(Duck typing)”。結(jié)構(gòu)精化類型(Structural refinement typing)是類似的,除了鴨子類型(如果它走起來像鴨子,叫起來像鴨子,就可以把它當(dāng)作鴨子)是運(yùn)行時(shí)類型,而這些結(jié)構(gòu)精化類型作用于編譯時(shí)。

在完全支持結(jié)構(gòu)精化類型的語言中,這些精化類型可以用在程序員可能期望的任何地方,例如方法參數(shù)的類型。而Java,相反地,不支持這樣的類型(除了幾個(gè)稍微怪異的邊緣例子)。

Java 5類型系統(tǒng)

Java 5的發(fā)布為類型系統(tǒng)帶來了三個(gè)主要新特性,枚舉、注解和泛型。

枚舉類型(Enum)在某些方面與類相似,但是它的屬性只能是指定數(shù)量的實(shí)例,每個(gè)實(shí)例都不同并且在類描述中指定。主要用于“類型安全的常量”,而不是當(dāng)時(shí)普遍使用的小整數(shù)常量,枚舉構(gòu)造同時(shí)還允許附加的模式,有時(shí)候這非常有用。

注解(Annotation)與接口相關(guān),聲明注解的關(guān)鍵字是@interface,以@開始表示這是個(gè)注解類型。正如名字所建議的,它們用于給Java代碼元素做注釋,提供附加信息,但不影響其行為。此前,Java曾使用“標(biāo)記接口(Marker interface)”來提供這種元數(shù)據(jù)的有限形式,但注解被認(rèn)為更有靈活性。

Java泛型提供了參數(shù)化類型,其想法是一種類型能扮演其它類型對(duì)象的“容器”,無需關(guān)心被包含類型的具體細(xì)節(jié)。裝配到容器中的類型通常稱為類型參數(shù)。

Java 5引入的特性中,枚舉和注解為引用類型提供了新的形式,這需要編譯器特殊處理,并且有效地從現(xiàn)有類型層級(jí)結(jié)構(gòu)分離。

泛型為Java的類型系統(tǒng)增加了顯著額外的復(fù)雜性,不僅僅因?yàn)樗鼈兪羌兇獾木幾g時(shí)特性,還要求Java開發(fā)人員應(yīng)注意,編譯時(shí)和運(yùn)行時(shí)的類型系統(tǒng)彼此略有不同。

盡管有這些變化,Java仍然保持標(biāo)明類型。類型名稱現(xiàn)在包括List(讀作:“List-of-String”)和Map, CachedObject>(“Map-of-Class-of-Unknown-Type-to-CachedObject”),但這些仍然是命名的類型,并且每個(gè)非基本類型的值仍是某個(gè)類的實(shí)例。

Java 6和7引入的特性

Java 6基本上是一個(gè)性能優(yōu)化和類庫增強(qiáng)的版本。類型系統(tǒng)的唯一變化是擴(kuò)大注解角色,發(fā)布可插拔注解處理功能。這對(duì)大多數(shù)開發(fā)者沒有任何影響,Java 6中也沒有真正提供可插拔類型系統(tǒng)。

Java 7的類型系統(tǒng)沒有重大改變。僅有的一些新特性,看起來都很相似:

javac編譯器中類型推斷的小改進(jìn)。

簽名多態(tài)性分派(Signature polymorphic dispatch),用于方法句柄(Method handle)的實(shí)現(xiàn)細(xì)節(jié),而這在Java 8中又反過來用于實(shí)現(xiàn)Lambda表達(dá)式。

Multi-catch提供了一些“代數(shù)數(shù)據(jù)類型”的小跟蹤信息,但這些完全是javac內(nèi)部的,對(duì)最終用戶程序員沒有任何影響。

Java 8的類型系統(tǒng)

縱觀其歷史,Java基本上已經(jīng)由其類型系統(tǒng)所定義。它是語言的核心,并且嚴(yán)格遵守著標(biāo)明類型。從實(shí)際情況來看,Java類型系統(tǒng)在Java 5和7之間沒有太大變化。

乍一看,我們可能期望Java 8改變這種狀況。畢竟,一個(gè)簡(jiǎn)單的Lambda表達(dá)式似乎讓我們移除了標(biāo)明類型:

() -> { System.out.println("Hello World!"); }

這是個(gè)沒有名字、沒有參數(shù)的方法,返回void。它仍然是完全靜態(tài)類型的,但現(xiàn)在是匿名的。

我們逃脫了名詞的王國?這真的是Java的一種新的類型形式?

也許不幸的是,答案是否定的。JVM上運(yùn)行的Java和其它語言,非常嚴(yán)格地限制在類的概念中。類加載是Java平臺(tái)的安全和驗(yàn)證模式的中心。簡(jiǎn)單地說,不通過類來表示一種類型,這是非常非常難的。

Java 8沒有創(chuàng)建新的類型,而是通過編譯器將Lambda表達(dá)式自動(dòng)轉(zhuǎn)換成一個(gè)類的實(shí)例。這個(gè)類由類型推斷來決定。例如:

Runnable r = () -> { System.out.println("Hello World!"); };

右側(cè)的Lambda表達(dá)式是個(gè)有效的Java 8的值,但其類型是根據(jù)左側(cè)值推斷的,因此它實(shí)際上是Runnable類型的值。需要注意的是,如果沒有正確地使用Lambda表達(dá)式,可能會(huì)導(dǎo)致編譯器錯(cuò)誤。即使是引入了Lambda,Java也沒有改變這一點(diǎn),仍然遵守著標(biāo)明類型。

Java 8的函數(shù)式編程怎么樣?

最后,讓我們回到本文開頭提出的問題,“Java 8的函數(shù)式編程怎么樣?”

Java 8之前,如果開發(fā)者想以函數(shù)式風(fēng)格編程,他或她只能使用嵌套類型(通常是匿名內(nèi)部類)作為函數(shù)代碼的替代。默認(rèn)的Collection類庫不會(huì)為這些代碼提供任何方便,可變性的魔咒也始終存在。

Java 8的Lambda表達(dá)式?jīng)]有神奇地轉(zhuǎn)變成函數(shù)式語言。相反,它的作用仍是創(chuàng)建強(qiáng)制的強(qiáng)命名類型語言,但有更好的語法支持Lambda表達(dá)式函數(shù)文本。與此同時(shí),Collection類庫也得到了增強(qiáng),允許Java開發(fā)人員開始采用簡(jiǎn)單的函數(shù)式風(fēng)格(例如filter和map)簡(jiǎn)化笨重的代碼。

Java 8需要引入一些新的類型來表示函數(shù)管道的基本構(gòu)造塊,如java.util.function中的Predicate、Function和Consumer接口。這些新增的功能使Java 8能夠“稍微函數(shù)式編程”,但Java需要用類型來表示它們(并且它們位于工具類包,而不是語言核心),這說明標(biāo)明類型仍然束縛著Java語言,它離純粹的Lisp方言或者其它函數(shù)式語言是多么的遙遠(yuǎn)。

除了以上這些,這個(gè)函數(shù)式語言能量的小集合很可能是所有大多數(shù)開發(fā)者日常開發(fā)所真正需要的。對(duì)于高級(jí)用戶,還有(JVM或其它平臺(tái))其它語言,并且毫無疑問,將繼續(xù)蓬勃發(fā)展。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“java8中函數(shù)式編程的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

網(wǎng)站名稱:java8中函數(shù)式編程的示例分析
URL分享:http://muchs.cn/article48/jepjhp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、移動(dòng)網(wǎng)站建設(shè)自適應(yīng)網(wǎng)站、網(wǎng)站導(dǎo)航、小程序開發(fā)、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站