本篇文章給大家分享的是有關(guān)java8中怎么實現(xiàn)lambada表達(dá)式和函數(shù)式編程,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供東豐網(wǎng)站建設(shè)、東豐做網(wǎng)站、東豐網(wǎng)站設(shè)計、東豐網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、東豐企業(yè)網(wǎng)站模板建站服務(wù),10多年東豐做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
直白的先讓大家有個第一印象,在java8之前,在創(chuàng)建一個線程的時候,我們可能這么寫:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};這段代碼使用了匿名類,Runnable 是一個接口,這里new 了一個類實現(xiàn)了 Runnable 接口,然后重寫了 run方法,run方法沒有參數(shù),方法體也只有一行打印語句。 這段代碼我們其實只關(guān)心中間打印的語句,其他都是多余的。 java8后,我們采用lambada表達(dá)式后,我們就可以簡寫為:
Runnable r = () -> System.out.println("Hello");Lambda 表達(dá)式是一種匿名函數(shù)(對 Java 而言這并不完全正確,但現(xiàn)在姑且這么認(rèn)為),簡單地說,它是沒有聲明的方法,也即沒有訪問修飾符、返回值聲明和名字。
你可以將其想做一種速記,在你需要使用某個方法的地方寫上它。當(dāng)某個方法只使用一次,而且定義很簡短,使用這種速記替代之尤其有效,這樣,你就不必在類中費力寫聲明與方法了。
lambda 表達(dá)式的語法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
一個 Lambda 表達(dá)式可以有零個或多個參數(shù)
參數(shù)的類型既可以明確聲明,也可以根據(jù)上下文來推斷。例如:(int a)與(a)效果相同
所有參數(shù)需包含在圓括號內(nèi),參數(shù)之間用逗號相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
空圓括號代表參數(shù)集為空。例如:() -> 42
當(dāng)只有一個參數(shù),且其類型可推導(dǎo)時,圓括號()可省略。例如:a -> return a*a
Lambda 表達(dá)式的主體可包含零條或多條語句
如果 Lambda 表達(dá)式的主體只有一條語句,花括號{}可省略。匿名函數(shù)的返回類型與該主體表達(dá)式一致
如果 Lambda 表達(dá)式的主體包含一條以上語句,則表達(dá)式必須包含在花括號{}中(形成代碼塊)。匿名函數(shù)的返回類型與代碼塊的返回類型一致,若沒有返回則為空
以下是lambada表達(dá)式的一些例子:
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };Java 是一流的面向?qū)ο笳Z言,除了部分簡單數(shù)據(jù)類型,Java 中的一切都是對象,即使數(shù)組也是一種對象,每個類創(chuàng)建的實例也是對象。 在 Java 中定義的函數(shù)或方法不可能完全獨立,也不能將方法作為參數(shù)或返回一個方法給實例。
在Java的面向?qū)ο蟮氖澜缋锩妫俺橄蟆笔菍?shù)據(jù)的抽象,而“函數(shù)式編程”是對行為進(jìn)行抽象,在現(xiàn)實世界中,數(shù)據(jù)和行為并存,程序也是如此。 所以java8中l(wèi)ambada表達(dá)式的出現(xiàn)也就彌補java在對行為進(jìn)行抽象方面的缺失。
函數(shù)式接口(Functional Interface)是Java 8對一類特殊類型的接口的稱呼。 這類接口只定義了唯一的抽象方法的接口(除了隱含的Object對象的公共方法), 因此最開始也就做SAM類型的接口(Single Abstract Method)。
首次看到這個概念的時候,有些迷茫。因為接口中的方法都是public abstract 的(即便省略掉這兩個關(guān)鍵字也是ok的,接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)),那么上面的定義就變成了:只有一個方法聲明的接口就是函數(shù)式接口。 但是實際上在代碼中看到的函數(shù)式接口有包含一個方法的,也有包含多個方法的,這就讓我迷茫了。 例如下面的兩個函數(shù)式接口:Runnable 和 Consummer:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}最后才了解了原因在于:函數(shù)式接口中除了那個抽象方法外還可以包含靜態(tài)方法和默認(rèn)方法。
Java 8以前的規(guī)范中接口中不允許定義靜態(tài)方法。 靜態(tài)方法只能在類中定義。 Java 8中可以定義靜態(tài)方法。 一個或者多個靜態(tài)方法不會影響SAM接口成為函數(shù)式接口。
Java 8中允許接口實現(xiàn)方法, 而不是簡單的聲明, 這些方法叫做默認(rèn)方法,使用特殊的關(guān)鍵字default。 因為默認(rèn)方法不是抽象方法,所以不影響我們判斷一個接口是否是函數(shù)式接口。
參考鏈接: Java 8函數(shù)式接口functional interface的秘密
為什么會單單從接口中定義出此類接口呢? 原因是在Java Lambda的實現(xiàn)中, 開發(fā)組不想再為Lambda表達(dá)式單獨定義一種特殊的Structural函數(shù)類型, 稱之為箭頭類型(arrow type), 依然想采用Java既有的類型系統(tǒng)(class, interface, method等), 原因是增加一個結(jié)構(gòu)化的函數(shù)類型會增加函數(shù)類型的復(fù)雜性, 破壞既有的Java類型,并對成千上萬的Java類庫造成嚴(yán)重的影響。 權(quán)衡利弊, 因此最終還是利用SAM 接口作為 Lambda表達(dá)式的目標(biāo)類型。
函數(shù)式接口代表的一種契約, 一種對某個特定函數(shù)類型的契約。 在它出現(xiàn)的地方,實際期望一個符合契約要求的函數(shù)。 Lambda表達(dá)式不能脫離上下文而存在,它必須要有一個明確的目標(biāo)類型,而這個目標(biāo)類型就是某個函數(shù)式接口。 換句話說:什么地方可以用lambada表達(dá)式呢? 所有需要FI (Functional Interface)實例的地方,都可以使用lambada表達(dá)式。
Java 不會強制要求你使用@FunctionalInterface注解來標(biāo)記你的接口是函數(shù)式接口, 然而,作為API作者, 你可能傾向使用@FunctionalInterface指明特定的接口為函數(shù)式接口, 這只是一個設(shè)計上的考慮, 可以讓用戶很明顯的知道一個接口是函數(shù)式接口。
說起函數(shù)式接口的起因就不得不提lambada表達(dá)式,說起lambada表達(dá)式的起因就不得不說函數(shù)式編程,函數(shù)式編程相比命令式編程有諸多的優(yōu)點:(最突出的優(yōu)點有2點: 引用透明-->函數(shù)的運行不依賴于外部的狀態(tài);沒有副作用-->函數(shù)的運行不改變外部的狀態(tài)),java8為了使用函數(shù)式編程的優(yōu)點,從而就使用了lambada表達(dá)式,從而 就定義了一種規(guī)范和約束,這個規(guī)范和約束就是函數(shù)式接口。 關(guān)于函數(shù)式編程的一些基礎(chǔ)概念會在下面將。(注意:函數(shù)式編程和函數(shù)式接口是不同的概念。函數(shù)式編程是一種編程范式,與之在同一個維度的有:命令式編程、邏輯式編程)
java.lang.Runnable
java.util.concurrent.callable
java.awt.event.ActionListener 這里就列舉這幾個,還有其他的暫時就不列舉了。
| 接口 | 參數(shù) | 返回類型 | 描述 |
|---|---|---|---|
| Predicate<T> | T | boolean | 用于判別一個對象。比如求一個人是否為男性 |
| Consumer<T> | T | void | 用于接收一個對象進(jìn)行處理但沒有返回,比如接收一個人并打印他的名字 |
| Function<T, R> | T | R | 轉(zhuǎn)換一個對象為不同類型的對象 |
| Supplier<T> | None | T | 提供一個對象 |
| UnaryOperator<T> | T | T | 接收對象并返回同類型的對象 |
| BinaryOperator<T> | (T, T) | T | 接收兩個同類型的對象,并返回一個原類型對象 |
其中 Cosumer 與 Supplier 對應(yīng),一個是消費者,一個是提供者。
Predicate 用于判斷對象是否符合某個條件,經(jīng)常被用來過濾對象。
Function 是將一個對象轉(zhuǎn)換為另一個對象,比如說要裝箱或者拆箱某個對象。
UnaryOperator 接收和返回同類型對象,一般用于對對象修改屬性。BinaryOperator 則可以理解為合并對象。
如果以前接觸過一些其他 Java 框架,比如 Google Guava,可能已經(jīng)使用過這些接口,對這些東西并不陌生。
命令式編程(Imperative Programming): 專注于”如何去做”,這樣不管”做什么”,都會按照你的命令去做。解決某一問題的具體算法實現(xiàn)。
函數(shù)式編程(Functional Programming):把運算過程盡量寫成一系列嵌套的函數(shù)調(diào)用。
邏輯式編程(Logical Programming):它設(shè)定答案須符合的規(guī)則來解決問題,而非設(shè)定步驟來解決問題。過程是事實+規(guī)則=結(jié)果。
關(guān)于這個問題也有一些爭議,有人把函數(shù)式歸結(jié)為聲明式的子集,還有一些別的七七八八的東西,這里就不做闡述了。 聲明式編程:專注于”做什么”而不是”如何去做”。在更高層面寫代碼,更關(guān)心的是目標(biāo),而不是底層算法實現(xiàn)的過程。 如, css, 正則表達(dá)式,sql 語句,html,xml…
相比于命令式編程關(guān)心解決問題的步驟,函數(shù)式編程是面向數(shù)學(xué)的抽象,關(guān)心數(shù)據(jù)(代數(shù)結(jié)構(gòu))之間的映射關(guān)系。函數(shù)式編程將計算描述為一種表達(dá)式求值。
在狹義上,函數(shù)式編程意味著沒有可變變量,賦值,循環(huán)和其他的命令式控制結(jié)構(gòu)。即,純函數(shù)式編程語言。
Pure Lisp, XSLT, XPath, XQuery, FP
Haskell (without I/O Monad or UnsafPerformIO) 在廣義上,函數(shù)式編程意味著專注于函數(shù)
Lisp, Scheme, Racket, Clojure
SML, Ocaml, F#
Haskell (full language)
Scala
Smalltalk, Ruby
函數(shù)式編程中的函數(shù),這個術(shù)語不是指命令式編程中的函數(shù),而是指數(shù)學(xué)中的函數(shù),即自變量的映射(一種東西和另一種東西之間的對應(yīng)關(guān)系)。 也就是說,一個函數(shù)的值僅決定于函數(shù)參數(shù)的值,不依賴其他狀態(tài)。
在函數(shù)式語言中,函數(shù)被稱為一等函數(shù)(First-class function),與其他數(shù)據(jù)類型一樣,作為一等公民,處于平等地位,可以在任何地方定義,在函數(shù)內(nèi)或函數(shù)外; 可以賦值給其他變量;可以作為參數(shù),傳入另一個函數(shù),或者作為別的函數(shù)的返回值。
純函數(shù)是這樣一種函數(shù),即相同的輸入,永遠(yuǎn)會得到相同的輸出,而且沒有任何可觀察的副作用。
不依賴外部狀態(tài)
不改變外部狀態(tài)
函數(shù)式的最主要的好處主要是不變性帶來的:
引用透明(Referential transparency),指的是函數(shù)的運行不依賴于外部變量或”狀態(tài)”,只依賴于輸入的參數(shù),任何時候只要參數(shù)相同, 引用函數(shù)所得到的返回值總是相同的。
其他類型的語言,函數(shù)的返回值往往與系統(tǒng)狀態(tài)有關(guān),不同的狀態(tài)之下,返回值是不一樣的。這就叫”引用不透明”,很不利于觀察和理解程序的行為。
沒有可變的狀態(tài),函數(shù)就是引用透明(Referential transparency)
副作用(side effect),指的是函數(shù)內(nèi)部與外部互動(最典型的情況,就是修改全局變量的值),產(chǎn)生運算以外的其他結(jié)果。
函數(shù)式編程強調(diào)沒有”副作用”,意味著函數(shù)要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。
函數(shù)即不依賴外部的狀態(tài)也不修改外部的狀態(tài),函數(shù)調(diào)用的結(jié)果不依賴調(diào)用的時間和位置,這樣寫的代碼容易進(jìn)行推理,不容易出錯。這使得單元測試和調(diào)試都更容易。
還有一個好處是,由于函數(shù)式語言是面向數(shù)學(xué)的抽象,更接近人的語言,而不是機器語言,代碼會比較簡潔,也更容易被理解。
沒有副作用使得函數(shù)式編程各個獨立的部分的執(zhí)行順序可以隨意打亂,(多個線程之間)不共享狀態(tài),不會造成資源爭用(Race condition), 也就不需要用鎖來保護(hù)可變狀態(tài),也就不會出現(xiàn)死鎖,這樣可以更好地進(jìn)行無鎖(lock-free)的并發(fā)操作。
尤其是在對稱多處理器(SMP)架構(gòu)下能夠更好地利用多個處理器(核)提供的并行處理能力。
惰性求值(lazy evaluation,也稱作call-by-need)是這樣一種技術(shù):是在將表達(dá)式賦值給變量(或稱作綁定)時并不計算表達(dá)式的值, 而在變量第一次被使用時才進(jìn)行計算。
這樣就可以通過避免不必要的求值提升性能。
總而言之,函數(shù)式編程由于其不依賴、不改變外部狀態(tài)的基本特性,衍生出了很多其他的有點,尤其簡化了多線程的復(fù)雜性,提升了高并發(fā)編程的可靠性。
以上就是java8中怎么實現(xiàn)lambada表達(dá)式和函數(shù)式編程,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
新聞標(biāo)題:java8中怎么實現(xiàn)lambada表達(dá)式和函數(shù)式編程
URL鏈接:http://www.yijiale78.com/article38/joocpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、響應(yīng)式網(wǎng)站、虛擬主機、App開發(fā)、網(wǎng)站導(dǎo)航、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)