這篇文章主要介紹了java8中函數(shù)式編程的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網站建設、域名、雅安服務器托管、網站托管、企業(yè)網站設計、皋蘭網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
函數(shù)式編程語言是什么?
函數(shù)式編程語言的核心是它以處理數(shù)據的方式處理代碼。這意味著函數(shù)應該是第一等級(First-class)的值,并且能夠被賦值給變量,傳遞給函數(shù)等等。
事實上,很多函數(shù)式語言比這走得更遠,將計算和算法看得比它們操作的數(shù)據更重要。其中有些語言想分離程序狀態(tài)和函數(shù)(以一種看起來有點對立的方式,使用面向對象的語言,這通常會將它們聯(lián)系得更緊密)。
Clojure編程語言就是一個這樣的例子,盡管它運行于基于類的Java虛擬機,Clojure的本質是函數(shù)式語言,并且在高級語言源程序中不直接公布類和對象(盡管提供了與Java良好的互操作性)。
下面顯示的是一個Clojure函數(shù),用于處理日志,是一等公民(First-class citizen),并且不需要綁定一個類而存在。
(defn build-map-http-entries [log-file] (group-by :uri (scan-log-for-http-entries log-file)))
當寫在函數(shù)中的程序,對給定的輸入(不論程序中的其它狀態(tài)如何)總是返回相同的輸出,并且不會產生其它影響,或者改變任何程序狀態(tài),這時候函數(shù)式編程是最有用的。它們的行為與數(shù)學函數(shù)相同,有時候把遵循這個標準的函數(shù)稱為“純”函數(shù)。
純函數(shù)的巨大好處是它們更容易推論,因為它們的操作不依賴于外部狀態(tài)。函數(shù)能夠很容易地結合在一起,這在開發(fā)者工作流風格中很常見,例如Lisp方言和其它具有強函數(shù)傳統(tǒng)的語言中很普遍的REPL(Read, Execute, Print, Loop)風格。
非函數(shù)式編程語言中的函數(shù)式編程
一種語言是不是函數(shù)式并不是非此即彼的狀態(tài),實際上,語言存在于圖譜上。在最末端,基本上是強制函數(shù)式編程,通常禁止可變的數(shù)據結構。Clojure就是一種不接受可變數(shù)據的語言。
不過,也有一些其它語言,通常以函數(shù)方式編程,但語言并不強制這一點。Scala就是一個例子,它混和了面向對象和函數(shù)式語言。允許函數(shù)作為值,例如:
val sqFn = (x: Int) => x * x
同時保留與Java非常接近的類和對象語法。
另一個極端,當然,使用完全非函數(shù)式語言進行函數(shù)式編程是可能的,例如C語言,只要維持好合適的程序員準則和慣例。
考慮到這一點,函數(shù)式編程應該被看作是有兩個因素的函數(shù),其中一個與編程語言相關,另一個是用該語言編寫的程序:
1)底層編程語言在多大程度上支持,或者強制函數(shù)式編程?
2)這個特定的程序如何使用語言提供的函數(shù)式特性?它是否避免了非函數(shù)式特性,例如可變狀態(tài)?
Java的一些歷史
Java是一種固執(zhí)己見的語言,它具有很好的可讀性,初級程序員很容易上手,具有長期穩(wěn)定性和可支持性。但這些設計決定也付出了一定的代價:冗長的代碼,類型系統(tǒng)與其它語言相比顯得缺乏彈性。
然而,Java的類型系統(tǒng)已經在演化,雖然在語言的歷史當中相對比較慢。我們來看看這些年來它的一些形式。
Java最初的類型系統(tǒng)
Java最初的類型系統(tǒng)至今已經超過15年了。它簡單而清晰,類型包括引用類型和基本類型。類、接口或者數(shù)組屬于引用類型。
類是Java平臺的核心,類是Java平臺將會加載、或鏈接的功能的基本單位,所有要執(zhí)行的代碼都必須駐留于一個類中。
接口不能直接實例化,而是要通過一個實現(xiàn)了接口API的類。
數(shù)組可以包含基本類型、類的實例或者其它數(shù)組。
基本類型全部由平臺定義,程序員不能定義新的基本類型。
從最早開始,Java的類型系統(tǒng)一直堅持很重要的一點,每一種類型都必須有一個可以被引用的名字。這被稱為“標明類型(Nominative typing)”,Java是一種強標明類型語言。
即使是所謂的“匿名內部類”也仍然有類型,程序員必須能引用它們,才能實現(xiàn)那些接口類型:
Runnable r = new Runnable() { public void run() { System.out.println("Hello World!"); } };
換種說法,Java中的每個值要么是基本類型,要么是某個類的實例。
命名類型(Named Type)的其它選擇
其它語言沒有這么迷戀命名類型。例如,Java沒有這樣的Scala概念,一個實現(xiàn)(特定簽名的)特定方法的類型。在Scala中,可以這樣寫:
x : {def bar : String}
記住,Scala在右側標示變量類型(冒號后面),所以這讀起來像是“x是一種類型,它有一個方法bar返回String”。我們能用它來定義類似這樣的Scala方法:
def showRefine(x : {def bar : String}) = { print(x.bar) }
然后,如果我們定義一個合適的Scala對象:
object barBell { def bar = "Bell" }
然后調用showRefine(barBell),這就是我們期待的事:
showRefine(barBell) Bell
這是一個精化類型(Refinement typing)的例子。從動態(tài)語言轉過來的程序員可能熟悉“鴨子類型(Duck typing)”。結構精化類型(Structural refinement typing)是類似的,除了鴨子類型(如果它走起來像鴨子,叫起來像鴨子,就可以把它當作鴨子)是運行時類型,而這些結構精化類型作用于編譯時。
在完全支持結構精化類型的語言中,這些精化類型可以用在程序員可能期望的任何地方,例如方法參數(shù)的類型。而Java,相反地,不支持這樣的類型(除了幾個稍微怪異的邊緣例子)。
Java 5類型系統(tǒng)
Java 5的發(fā)布為類型系統(tǒng)帶來了三個主要新特性,枚舉、注解和泛型。
枚舉類型(Enum)在某些方面與類相似,但是它的屬性只能是指定數(shù)量的實例,每個實例都不同并且在類描述中指定。主要用于“類型安全的常量”,而不是當時普遍使用的小整數(shù)常量,枚舉構造同時還允許附加的模式,有時候這非常有用。
注解(Annotation)與接口相關,聲明注解的關鍵字是@interface,以@開始表示這是個注解類型。正如名字所建議的,它們用于給Java代碼元素做注釋,提供附加信息,但不影響其行為。此前,Java曾使用“標記接口(Marker interface)”來提供這種元數(shù)據的有限形式,但注解被認為更有靈活性。
Java泛型提供了參數(shù)化類型,其想法是一種類型能扮演其它類型對象的“容器”,無需關心被包含類型的具體細節(jié)。裝配到容器中的類型通常稱為類型參數(shù)。
Java 5引入的特性中,枚舉和注解為引用類型提供了新的形式,這需要編譯器特殊處理,并且有效地從現(xiàn)有類型層級結構分離。
泛型為Java的類型系統(tǒng)增加了顯著額外的復雜性,不僅僅因為它們是純粹的編譯時特性,還要求Java開發(fā)人員應注意,編譯時和運行時的類型系統(tǒng)彼此略有不同。
盡管有這些變化,Java仍然保持標明類型。類型名稱現(xiàn)在包括List(讀作:“List-of-String”)和Map, CachedObject>(“Map-of-Class-of-Unknown-Type-to-CachedObject”),但這些仍然是命名的類型,并且每個非基本類型的值仍是某個類的實例。
Java 6和7引入的特性
Java 6基本上是一個性能優(yōu)化和類庫增強的版本。類型系統(tǒng)的唯一變化是擴大注解角色,發(fā)布可插拔注解處理功能。這對大多數(shù)開發(fā)者沒有任何影響,Java 6中也沒有真正提供可插拔類型系統(tǒng)。
Java 7的類型系統(tǒng)沒有重大改變。僅有的一些新特性,看起來都很相似:
javac編譯器中類型推斷的小改進。
簽名多態(tài)性分派(Signature polymorphic dispatch),用于方法句柄(Method handle)的實現(xiàn)細節(jié),而這在Java 8中又反過來用于實現(xiàn)Lambda表達式。
Multi-catch提供了一些“代數(shù)數(shù)據類型”的小跟蹤信息,但這些完全是javac內部的,對最終用戶程序員沒有任何影響。
Java 8的類型系統(tǒng)
縱觀其歷史,Java基本上已經由其類型系統(tǒng)所定義。它是語言的核心,并且嚴格遵守著標明類型。從實際情況來看,Java類型系統(tǒng)在Java 5和7之間沒有太大變化。
乍一看,我們可能期望Java 8改變這種狀況。畢竟,一個簡單的Lambda表達式似乎讓我們移除了標明類型:
() -> { System.out.println("Hello World!"); }
這是個沒有名字、沒有參數(shù)的方法,返回void。它仍然是完全靜態(tài)類型的,但現(xiàn)在是匿名的。
我們逃脫了名詞的王國?這真的是Java的一種新的類型形式?
也許不幸的是,答案是否定的。JVM上運行的Java和其它語言,非常嚴格地限制在類的概念中。類加載是Java平臺的安全和驗證模式的中心。簡單地說,不通過類來表示一種類型,這是非常非常難的。
Java 8沒有創(chuàng)建新的類型,而是通過編譯器將Lambda表達式自動轉換成一個類的實例。這個類由類型推斷來決定。例如:
Runnable r = () -> { System.out.println("Hello World!"); };
右側的Lambda表達式是個有效的Java 8的值,但其類型是根據左側值推斷的,因此它實際上是Runnable類型的值。需要注意的是,如果沒有正確地使用Lambda表達式,可能會導致編譯器錯誤。即使是引入了Lambda,Java也沒有改變這一點,仍然遵守著標明類型。
Java 8的函數(shù)式編程怎么樣?
最后,讓我們回到本文開頭提出的問題,“Java 8的函數(shù)式編程怎么樣?”
Java 8之前,如果開發(fā)者想以函數(shù)式風格編程,他或她只能使用嵌套類型(通常是匿名內部類)作為函數(shù)代碼的替代。默認的Collection類庫不會為這些代碼提供任何方便,可變性的魔咒也始終存在。
Java 8的Lambda表達式沒有神奇地轉變成函數(shù)式語言。相反,它的作用仍是創(chuàng)建強制的強命名類型語言,但有更好的語法支持Lambda表達式函數(shù)文本。與此同時,Collection類庫也得到了增強,允許Java開發(fā)人員開始采用簡單的函數(shù)式風格(例如filter和map)簡化笨重的代碼。
Java 8需要引入一些新的類型來表示函數(shù)管道的基本構造塊,如java.util.function中的Predicate、Function和Consumer接口。這些新增的功能使Java 8能夠“稍微函數(shù)式編程”,但Java需要用類型來表示它們(并且它們位于工具類包,而不是語言核心),這說明標明類型仍然束縛著Java語言,它離純粹的Lisp方言或者其它函數(shù)式語言是多么的遙遠。
除了以上這些,這個函數(shù)式語言能量的小集合很可能是所有大多數(shù)開發(fā)者日常開發(fā)所真正需要的。對于高級用戶,還有(JVM或其它平臺)其它語言,并且毫無疑問,將繼續(xù)蓬勃發(fā)展。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“java8中函數(shù)式編程的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關知識等著你來學習!
網站名稱:java8中函數(shù)式編程的示例分析
URL分享:http://www.rwnh.cn/article48/jepjhp.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供微信小程序、移動網站建設、自適應網站、網站導航、小程序開發(fā)、用戶體驗
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)