在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    現(xiàn)代編程語言都具備的Lambda到底是個啥?詳聊Lambda與函數(shù)式接口

    1. Lambda

    咱們首先來說說 Lambda 這個名字,Lambda 并不是一個什么的縮寫,它是希臘第十一個字母 λ 的讀音,同時它也是微積分函數(shù)中的一個概念,所表達(dá)的意思是一個函數(shù)入?yún)⒑统鰠?span id="sjy83hs" class="wpcom_tag_link">定義,在編程語言中其實是借用了數(shù)學(xué)中的 λ,并且多了一點含義,在編程語言中功能代表它具體功能的叫法是匿名函數(shù)(Anonymous Function),根據(jù)百科的解釋:

    匿名函數(shù)(英語:Anonymous Function)在計算機編程中是指一類無需定義標(biāo)識符(函數(shù)名)的函數(shù)或子程序。

    到這我們應(yīng)該看懂了,在編程語言中引入了 λ 的數(shù)學(xué)中的意思后,還加入了“匿名”這個概念,為什么要加它呢?顯然是為了讓開發(fā)者寫起來更加方便,不必去想具體的函數(shù)名,尤其是在流式表達(dá)中,匿名能讓你更加高效。

    接著再來說說Lambda 的歷史,雖然它在 JDK8 發(fā)布之后才正式出現(xiàn),但是在編程語言界,它是一個具有悠久歷史的東西,最早在 1958 年在Lisp 語言中首先采用,而且雖然Java脫胎于C++,但是C++在2011年已經(jīng)發(fā)布了Lambda 了,但是 JDK8 的 LTS 在2014年才發(fā)布,所以 Java 被人叫做老土不是沒有原因的,現(xiàn)代編程語言則是全部一出生就自帶 Lambda 支持,所以Lambda 其實是越來越火的一個節(jié)奏~

    那么Lambda 到底好在哪?不用寫函數(shù)名?其實我覺得要回答這個問題首先要明白Lambda 在編程語言方面到底是什么?

    上面也說了,Lambda 在編程語言中往往是一個匿名函數(shù),也就是說Lambda 是一個抽象概念,而編程語言提供了配套支持,比如在 Java 中其實為Lambda 進行配套的就是函數(shù)式接口,通過函數(shù)式接口生成匿名類和方法進行Lambda 式的處理。

    那么,既然是這一套規(guī)則我們明白了,那么Lambda 所提供的好處在Java中就是函數(shù)式接口所提供的能力了,函數(shù)式接口往往則是提供了一些通用能力,這些函數(shù)式接口在JDK中也有一套完整的實踐,那就是 Stream。

    Stream 提供了一套完整的流式處理方法幫助我們進行流式調(diào)用,熟悉Stream 的讀者應(yīng)該知道使用它能帶來多么大的便捷,更多關(guān)于 Stream 的知識可以看我的 延遲執(zhí)行與不可變,系統(tǒng)講解JavaStream數(shù)據(jù)處理 ,在這篇文章中有著詳細(xì)的敘述。

    那么總結(jié)起來,Lambda 在Java中所提供的好處就是使用函數(shù)式接口對一些問題進行了抽象,從而得到了一些通用能力,這些通用能力就是使用Lambda 最大的好處,下面將會具體講解JDK中都定義了哪些通用能力,看到這的小伙伴可以給本文點個贊,以示鼓勵。

    2. 函數(shù)式接口

    在 Java 中,所有的函數(shù)式接口都是以 @Functionallnterface 進行標(biāo)注的,就像這樣:

    @FunctionalInterfacepublic interface Runnable { public abstract void run();}復(fù)制代碼

    在一個接口上打上 @Functionallnterface并且定義一個抽象方法,這樣的類我們就稱之為函數(shù)式接口,當(dāng)然這個方法并不一定非要用抽象關(guān)鍵字來修飾,比如:

    @FunctionalInterfacepublic interface Consumer { void accept(T t);}復(fù)制代碼

    當(dāng)然,不寫 @Functionallnterface 注解其實也沒關(guān)系,但是需要保證,這個接口只定義了一個抽象方法,接口的默認(rèn)方法不算,那個可以稱得上是接口的靜態(tài)方法了。

    為什么只能有一個抽象方法呢?因為你的自定義邏輯就是這個方法的匿名函數(shù),最終會調(diào)用這個方法,所以只能有一個。

    然后你就可以使用 Lambda 表達(dá)式來進行書寫了,就像這樣:

    Thread thread = new Thread(() -> { });復(fù)制代碼

    看吧,很方便的寫法就定義了一個Runnable 的匿名子類出來,不過 Runnable 這種使用Lambda 只是為了生成一個匿名子類的情況確實無法完全發(fā)揮Lambda 的作用,Lambda 更大的作用還是在解決具體的問題上,而非創(chuàng)造一個匿名類。

    舉個例子,假如你想定義一個對商品數(shù)據(jù)進行商品篩查的函數(shù),那么它可能是這樣的:

    public List filter(List list, String type) { List result = new ArrayList(); for (Goods goods : list) { if (goods.getType().equals(type)) { result.add(goods); } } return result; }復(fù)制代碼

    ok,看起來一切沒問題,但是架不住需求改變啊,很快你又需要定義一個對商品金額進行篩查的方法,那么它可能是這樣的:

    public List gt(List list, Integer price) { List result = new ArrayList(); for (Goods goods : list) { if (goods.getPrice() > price) { result.add(goods); } } return result; }復(fù)制代碼

    那么你可以發(fā)現(xiàn):大部分代碼基本沒變,只有入?yún)⒑团袛噙壿嫲l(fā)生了一點改變,這個時候你可能會想,能不能把判斷邏輯直接抽象成一個匿名函數(shù),每次只需要簡單寫一個這個判斷函數(shù)即可,再把方法入?yún)⒎庋b成一個東西,在任何場景下都可以使用。

    看到這,你可能就有點明白了,因為在Java8 已經(jīng)提供了Stream流去做這件事,上面這個場景其實對應(yīng)的是Stream 中的filter 方法,而filter 方法的入?yún)⒕褪且粋€函數(shù)式接口——Predicate。

    還沒明白嗎?那我說的再清楚一點,Predicate 抽象了判斷這個場景,而且這種抽象不局限于業(yè)務(wù),是直接對某一類場景進行抽象,比如篩選商品類別,篩選商品大于某個金額或者小于某個金額,它不在糾結(jié)你到底想要怎么篩選,而是直接對篩選函數(shù)進行抽象,得到了Predicate,你想怎么篩選你自己寫,剩下的交給它,它將一勞永逸的解決這類問題,當(dāng)然這里面還有一部分 Stream 的功勞,不過主要思想還是 Predicate 在做,Stream 這里我們暫且不提。

    像這種對于某個場景進行頂級抽象的函數(shù)式接口,JDK一共提供了四個:

  • Consumer
  • Supplier
  • Predicate
  • Function
  • 接下來我將一一為大家進行講述,除了這四個之外還有大量的衍生函數(shù)式接口,在JDK8中就有50個左右,不過都是在這四個基礎(chǔ)上進行修改,不必?fù)?dān)心記不住的問題。

    3. Consumer

    **Consumer **通過名字可以看出它是一個消費函數(shù)式接口,主要針對的是消費這個場景,它的代碼定義如下:

    @FunctionalInterfacepublic interface Consumer { void accept(T t);}復(fù)制代碼

    通過泛型 T 定義了一個入?yún)?,但是沒有返回值,它代表你可以針對這個入?yún)⒆鲆恍┳远x邏輯,比較典型的例子是 Stream 中的 forEach 方法。

    而我們的主要使用場景也往往是循環(huán)進行某項操作,比如有一堆手機號,循環(huán)進行發(fā)短信。

    所以消費場景是 Consumer 的主要用武之地,但是有時候你還面臨一個問題,一個入?yún)⑺坪跆倭耍袝r候你需要對兩個對象進行操作,又懶得將它們合并成一個對象,這種情況 JDK 提供了 BiConsumer:

    @FunctionalInterfacepublic interface BiConsumer { void accept(T t, U u);}復(fù)制代碼

    這種你可以直接傳進去兩個參數(shù)了,什么?你想要三個參數(shù)的?那沒有,三個或者三個以上我感覺就有必要合并成一個對象進行消費了。

    除了這兩個之外,還有DoubleConsumer、IntConsumer和LongConsumer這種限定了入?yún)㈩愋偷?Consumer,這里不再多述。

    4. Supplier

    Supplier通過名字比較難看出來它是一個場景的函數(shù)式接口,它主要針對的是get這個場景或者說獲取這個場景,它的代碼定義如下:

    @FunctionalInterfacepublic interface Supplier { T get();}復(fù)制代碼

    通過泛型 T 定義了一個返回值類型,但是沒有入?yún)?,它代表你可以針對調(diào)用方獲取某個值,比較典型的例子是 Stream 中的 collect 方法,通過自定義傳入我們想要取得的某種對象進行對象收集。

    而我們的主要使用場景也往往是收集和聚合這個場景了,這個場景我們也是對獲得這個場景進行收集。

    和Consumer一樣,Supplier還具有以下衍生接口:

  • BooleanSupplier
  • DoubleSupplier
  • IntSupplier
  • LongSupplier
  • 都是提前對獲取的定義好了數(shù)據(jù)類型,思想一致,這里不再多述。

    5. Predicate

    Predicate前文我們已經(jīng)介紹過,它主要針對的是判斷這個場景,它的代碼定義如下:

    @FunctionalInterfacepublic interface Predicate { boolean test(T t);}復(fù)制代碼

    通過泛型 T 定義了一個入?yún)ⅲ祷亓艘粋€布爾值,它代表你可以傳入一段判斷邏輯的函數(shù),比較典型的例子是 Stream 中的 filter方法。

    我們對于它的使用場景實在是太多了,基本上做任何業(yè)務(wù)都有在內(nèi)存中進行篩選 or 判斷的場景。

    所以判斷和篩選場景是 Predicate的主要用武之地,但是有時候你還面臨和上面一樣的問題,一個入?yún)⑺坪跆倭耍袝r候你需要對兩個對象進行操作,又懶得將它們合并成一個對象,這種情況 JDK 提供了 BiPredicate:

    @FunctionalInterfacepublic interface BiPredicate { boolean test(T t, U u);}復(fù)制代碼

    這種你可以直接傳進去兩個參數(shù)進行函數(shù)的自定義邏輯。

    除了這兩個之外,還有DoublePredicate、IntPredicate和LongPredicate這種限定了入?yún)㈩愋偷腜redicate,這里不再多述。

    6. Function

    Function 接口的名字不太能輕易看出來它的場景,它主要針對的則是 轉(zhuǎn)換這個場景,其實說轉(zhuǎn)換可能也不太正確,它是一個覆蓋范圍比較廣的場景,你也可以理解為擴展版的Consumer,接口定義如下:

    @FunctionalInterfacepublic interface Function { R apply(T t);}復(fù)制代碼

    通過一個入?yún)?T 進行自定義邏輯處理,最終得到一個出參 R,比較典型的例子是 Stream 中的 map 系列方法和 reduce 系列方法。

    為什么我說也可以理解為一個擴展版的Consumer呢?我們還舉例手機號發(fā)短信的場景好了,你通過循環(huán)發(fā)完短信之后可能想拿到發(fā)完短信之后的結(jié)果對象,來進行后續(xù)處理。

    這個時候單純的Consumer就不行了,因為它沒有返回值,你就可以通過 Function 這種函數(shù)式對象進行處理了。

    和 Consumer 一樣,F(xiàn)unction 也有一個衍生接口可以通過兩個入?yún)⒎祷匾粋€對象——BiFunction。

    還有一些定義好了入?yún)⒑统鰠⒌?Function

  • 延遲執(zhí)行與不可變,系統(tǒng)講解JavaStream數(shù)據(jù)處理
  • 歸約、分組與分區(qū),深入講解JavaStream終結(jié)操作
  • 鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    用戶投稿
    上一篇 2022年7月24日 17:05
    下一篇 2022年7月24日 17:05

    相關(guān)推薦

    • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

      對于微商朋友來說,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營一個朋友圈,有的微商看起來逼格滿滿,實際效果也不錯;而有的卻動都不動就被屏蔽甚至拉黑…

      2022年11月27日
    • 存儲過程語法(sql server存儲過程語法)

      今天小編給各位分享存儲過程語法的知識,其中也會對sql server存儲過程語法進行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧! oracle存儲過程基本語法…

      2022年11月26日
    • 《寶可夢朱紫》夢特性怎么獲得?隱藏特性獲取方法推薦

      寶可夢朱紫里有很多寶可夢都是擁有夢特性會變強的寶可夢,很多玩家不知道夢特性怎么獲得,下面就給大家?guī)韺毧蓧糁熳想[藏特性獲取方法推薦,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 …

      2022年11月25日
    • 《寶可夢朱紫》奇魯莉安怎么進化?奇魯莉安進化方法分享

      寶可夢朱紫中的奇魯莉安要怎么進化呢?很多玩家都不知道,下面就給大家?guī)韺毧蓧糁熳掀骠斃虬策M化方法分享,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 奇魯莉安進化方法分享 奇魯莉安…

      2022年11月25日
    • 成都健康碼打不開顯示接口請求未知異常怎么辦(成都健康碼打不開顯示接口請求未知異常)

      成都這幾天的疫情也是備受關(guān)注,疫情期間各地出行都是需要查看健康碼的,不過今天卻有成都的小伙伴反饋健康碼無法打開的情況。成都健康碼打不開顯示接口請求未知異常怎么辦?由于健康碼無法打開…

      2022年11月24日
    • 1千克等于多少磅

      克,此定義在1958年被美國以及其他英聯(lián)邦會員國承認(rèn)換算回來,一千克等于262磅,一磅等于037千克英國在1963年開始,依據(jù)度量衡法案的規(guī);1 磅=16 盎司=04536 千克 …

      2022年11月24日
    • 《寶可夢朱紫》暴飛龍怎么抓?暴飛龍獲得方法

      寶可夢朱紫暴飛龍位置在哪?在游戲中,很多玩家還不清楚暴飛龍具體要怎么樣獲得,其實獲得方法很簡單,暴飛龍直接是沒得抓的,需要玩家從寶貝龍進化得到,下面一起來看一下寶可夢朱紫暴飛龍獲得…

      2022年11月23日
    • 《寶可夢朱紫》布土撥怎么進化?布土撥進化方法介紹

      寶可夢朱紫中,不同的寶可夢有不同的進化方法,其中布土撥的進化方法是比較特殊的。很多玩家不知道寶可夢朱紫布土撥怎么進化,下面就帶來寶可夢朱紫布土撥進化方法介紹,一起來看看吧,希望能幫…

      2022年11月23日
    • 《寶可夢朱紫》薄荷怎么獲得?薄荷獲得方法

      寶可夢朱紫中薄荷有改變寶可夢的屬性或性格等效果,很多玩家想知道寶可夢朱紫薄荷怎么獲得,下面就帶來寶可夢朱紫薄荷獲得方法,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 薄荷獲得方法…

      2022年11月23日
    • 《寶可夢朱紫》怎么交換精靈?交換精靈方法一覽

      寶可夢朱紫中玩家可以和好友或者npc進行交換寶可夢獲得自己沒有的寶可夢,很多玩家想知道寶可夢朱紫怎么交換精靈,下面就帶來寶可夢朱紫交換精靈方法一覽,感興趣的小伙伴不要錯過,希望能幫…

      2022年11月23日

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息