Java 8 Lambda 表達(dá)式相關(guān)

Java 8 之后推出的 Lambda 表達(dá)式開(kāi)啟了 Java 語(yǔ)言支持函數(shù)式編程(Functional Programming)的新時(shí)代穿香。

Lambda 表達(dá)式亭引,也稱為閉包(Closure),現(xiàn)在很多語(yǔ)言都支持 Lambda表達(dá)式皮获,如 C++焙蚓、C#、Swift洒宝、Objective-C 和 JavaScript 等购公。為什么 Lambda 表達(dá)式這怎么受歡迎,這是因?yàn)長(zhǎng)ambda表達(dá)式是實(shí)現(xiàn)支持函數(shù)式編程技術(shù)基礎(chǔ)雁歌。

函數(shù)式編程與面向?qū)ο缶幊逃泻艽蟮牟顒e宏浩,函數(shù)式編程將程序代碼看作數(shù)學(xué)中的函數(shù),函數(shù)本身作為另一個(gè)函數(shù)的參數(shù)或返回值将宪,即高階函數(shù)绘闷。而面向?qū)ο缶幊淌前凑照鎸?shí)世界客觀事物的自然規(guī)律進(jìn)行分析橡庞,客觀世界中存在什么樣的實(shí)體,構(gòu)建的軟件系統(tǒng)就存在什么樣的實(shí)體印蔗。即便 Java 8 之后提供了對(duì)函數(shù)式編程的支持扒最,但是 Java 還是以面向?qū)ο鬄橹鞯恼Z(yǔ)言,函數(shù)式編程只是對(duì) Java 語(yǔ)言的補(bǔ)充华嘹。

Lambda 表達(dá)式概述

簡(jiǎn)單來(lái)說(shuō)吧趣,Lambda 表達(dá)式是創(chuàng)建匿名內(nèi)部類(lèi)的語(yǔ)法糖(syntax sugar)。在編譯器的幫助下耙厚,可以讓開(kāi)發(fā)人員用更少的代碼來(lái)完成工作强挫。

Lambda表達(dá)式標(biāo)準(zhǔn)語(yǔ)法形式如下:

(參數(shù)列表) -> {
    //Lambda表達(dá)式體
}

舉例

// Lambda表達(dá)式實(shí)現(xiàn)Calculable接口
result = (int a, int b) -> {                    
    return a + b;
};

函數(shù)式接口(Functional Interface)

Lambda 表達(dá)式實(shí)現(xiàn)的接口不是普通的接口,稱為是函數(shù)式接口薛躬,這種接口只能有一個(gè)方法俯渤。

在講Lambda表達(dá)式的時(shí)候提到過(guò),所謂的函數(shù)式接口型宝,當(dāng)然首先是一個(gè)接口八匠,然后就是在這個(gè)接口里面只能有一個(gè)抽象方法

這種類(lèi)型的接口也稱為SAM接口趴酣,即 Single Abstract Method interfaces梨树。

為了防止在函數(shù)式接口中聲明多個(gè)抽象方法,Java 8提供了一個(gè)聲明函數(shù)式接口注解 @FunctionalInterface岖寞,用于編譯級(jí)錯(cuò)誤檢查抡四。這樣如果接口中聲明多個(gè)抽象方法,那么Lambda表達(dá)式會(huì)發(fā)生編譯錯(cuò)誤:The target type of this expression must be a functional interface仗谆。

// Calculable.java文件

@FunctionalInterface
public interface Calculable {
    // 計(jì)算兩個(gè)int數(shù)值
    int calculateInt(int a, int b);
}

注意:加不加@FunctionalInterface對(duì)于接口是不是函數(shù)式接口沒(méi)有影響指巡,該注解知識(shí)提醒編譯器去檢查該接口是否僅包含一個(gè)抽象方法

函數(shù)式接口用途

它們主要用在 Lambda 表達(dá)式和方法引用(實(shí)際上也可認(rèn)為是Lambda表達(dá)式)上。

那么就可以使用Lambda表達(dá)式來(lái)表示該接口的一個(gè)實(shí)現(xiàn)(注:JAVA 8 之前一般是用匿名類(lèi)實(shí)現(xiàn)的)胸私。

函數(shù)式接口里是可以包含默認(rèn)方法

因?yàn)槟J(rèn)方法不是抽象方法厌处,其有一個(gè)默認(rèn)實(shí)現(xiàn),所以是符合函數(shù)式接口的定義的岁疼;

函數(shù)式接口里允許定義 java.lang.Object 里的 public 方法

函數(shù)式接口里是可以包含 Object 里的 public 方法阔涉,這些方法對(duì)于函數(shù)式接口來(lái)說(shuō),不被當(dāng)成是抽象方法(雖然它們是抽象方法)捷绒;因?yàn)槿魏我粋€(gè)函數(shù)式接口的實(shí)現(xiàn)瑰排,默認(rèn)都繼承了 Object 類(lèi),包含了來(lái)自 java.lang.Object 里對(duì)這些抽象方法的實(shí)現(xiàn)暖侨。

JDK中的函數(shù)式接口舉例

  • java.lang.Runnable,
  • java.awt.event.ActionListener,
  • java.util.Comparator,
  • java.util.concurrent.Callable
  • java.util.function包下的接口椭住,如Consumer、Predicate字逗、Supplier等京郑。

Lambda表達(dá)式簡(jiǎn)化形式

使用Lambda表達(dá)式是為了簡(jiǎn)化程序代碼宅广,Lambda 表達(dá)式本身也提供了多種簡(jiǎn)化形式,這些簡(jiǎn)化形式雖然簡(jiǎn)化了代碼些举,但客觀上使得代碼可讀性變差跟狱。本節(jié)介紹Lambda表達(dá)式本幾種簡(jiǎn)化形式。

  • 省略參數(shù)類(lèi)型, Lambda表達(dá)式可以根據(jù)上下文環(huán)境推斷出參數(shù)類(lèi)型
  • 省略參數(shù)小括號(hào), Lambda表達(dá)式中參數(shù)只有一個(gè)時(shí)可以省略
  • 如果Lambda表達(dá)式體中只有一條語(yǔ)句户魏,那么可以省略return和大括號(hào)
    例如result = a -> a * a; //省略形式

Lambda 表達(dá)式作為參數(shù)使用

Lambda 表達(dá)式一種常見(jiàn)的用途是作為參數(shù)傳遞給方法驶臊。這需要聲明參數(shù)的類(lèi)型為函數(shù)式接口類(lèi)型。

示例代碼如下:

public class HelloWorld {

    public static void main(String[] args) {
        int n1 = 10;
        int n2 = 5;                      
        // 打印計(jì)算結(jié)果減法計(jì)算結(jié)果
        display((a, b) -> a - b, n1, n2); 
    }

    /**
     * 打印計(jì)算結(jié)果
     *
     * @param calc Lambda表達(dá)式
     * @param n1 操作數(shù)1
     * @param n2 操作數(shù)2
     */
    static void display(Calculable calc, int n1, int n2) {        
        System.out.println(calc.calculateInt(n1, n2));
    }

}

Lambda 作用域

在lambda表達(dá)式中訪問(wèn)外層作用域和老版本的匿名對(duì)象中的方式很相似叼丑。你可以直接訪問(wèn)標(biāo)記了final的外層局部變量关翎,或者實(shí)例的字段以及靜態(tài)變量。

方法引用

Java 8之后增加了雙冒號(hào)“::”運(yùn)算符鸠信,該運(yùn)算符用于“方法引用”纵寝,注意不是調(diào)用方法⌒橇ⅲ“方法引用”雖然沒(méi)有直接使用 Lambda 表達(dá)式店雅,但也與 Lambda 表達(dá)式有關(guān),與函數(shù)式接口有關(guān)贞铣。

方法引用的具體使用

java8方法引用有四種形式:

  1. 靜態(tài)方法引用       :   ClassName :: staticMethodName
  2. 構(gòu)造器引用       【诿鳌:   ClassName :: new
  3. 類(lèi)的任意對(duì)象的實(shí)例方法引用:   ClassName :: instanceMethodName
  4. 特定對(duì)象的實(shí)例方法引用 ≡印:   object :: instanceMethodName

注意 被引用方法的參數(shù)列表和返回值類(lèi)型,必須與函數(shù)式接口方法參數(shù)列表和方法返回值類(lèi)型一致荐健。

靜態(tài)方法引用 / 特定對(duì)象的實(shí)例方法適用于lambda表達(dá)式主體中僅僅調(diào)用了某個(gè)類(lèi)的靜態(tài)方法 / 對(duì)象的實(shí)例方法的情形酱畅。

構(gòu)造器引用適用于lambda表達(dá)式主體中僅僅調(diào)用了某個(gè)類(lèi)的構(gòu)造函數(shù)返回實(shí)例的場(chǎng)景。

類(lèi)的任意對(duì)象的實(shí)例方法引用的特性中江场,第一個(gè)入?yún)閷?shí)例方法的調(diào)用者纺酸,后面的入?yún)⑴c實(shí)例方法的入?yún)⒁恢隆?/p>

類(lèi)的任意對(duì)象的實(shí)例方法引用舉例:

// Supplier 要求void -> 出參。恰和對(duì)象.(VOID)->出參 匹配
String string = "12345";
Supplier<Integer> supplier = string::length;
System.out.println(supplier.get());

構(gòu)造器引用舉例:

// Supplier:void -> 出參:類(lèi)的;
Supplier<String> supplier = String::new;
System.out.println(supplier.get());

靜態(tài)方法引用 / 特定對(duì)象的實(shí)例方法舉例:

public class LambdaDemo {

    // 靜態(tài)方法址否,進(jìn)行加法運(yùn)算
    // 參數(shù)列表要與函數(shù)式接口方法calculateInt(int a, int b)兼容
    public static int add(int a, int b) {
        return a + b;
    }

    // 實(shí)例方法餐蔬,進(jìn)行減法運(yùn)算
    // 參數(shù)列表要與函數(shù)式接口方法calculateInt(int a, int b)兼容
    public int sub(int a, int b) {
        return a - b;
    }
}
public class HelloWorld {

    public static void main(String[] args) {
        int n1 = 10;
        int n2 = 5;

        // 打印計(jì)算結(jié)果加法計(jì)算結(jié)果
        display(LambdaDemo::add, n1, n2);                    

        LambdaDemo d = new LambdaDemo();
        // 打印計(jì)算結(jié)果減法計(jì)算結(jié)果
        display(d::sub, n1, n2);       
    }

    /**
     * 打印計(jì)算結(jié)果
     * @param calc Lambda表達(dá)式
     * @param n1  操作數(shù)1
     * @param n2 操作數(shù)2
     */
    public static void display(Calculable calc, int n1, int n2) {        
        System.out.println(calc.calculateInt(n1, n2));
    }
}

靜態(tài)的 display 方法,第一個(gè)參數(shù) calc 是 Calculable類(lèi)型佑附,它可以接受三種對(duì)象:Calculable實(shí)現(xiàn)對(duì)象樊诺、Lambda表達(dá)式方法引用

代碼第 ① 行中第一個(gè)實(shí)際參數(shù)LambdaDemo::add 是靜態(tài)方法的方法引用音同。
代碼第 ② 行中第一個(gè)實(shí)際參數(shù)d::sub,是實(shí)例方法的方法引用词爬,d是LambdaDemo實(shí)例。

提示: 代碼第①行的LambdaDemo::add和第②行的d::sub中Lambda是方法引用权均,此時(shí)并沒(méi)有調(diào)用方法顿膨,只是將引用傳遞給display方法锅锨,在display方法中才真正調(diào)用方法。

參考

第 18 章 Java 8函數(shù)式編程基礎(chǔ)——Lambda表達(dá)式-圖靈社區(qū)
http://www.ituring.com.cn/book/tupubarticle/17714

Java 8 的 Lambda 表達(dá)式和流處理 – IBM Developer
https://developer.ibm.com/zh/articles/j-understanding-functional-programming-3/

Java 8 十大新特性詳解java腳本之家
https://www.jb51.net/article/48304.htm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恋沃,一起剝皮案震驚了整個(gè)濱河市必搞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芽唇,老刑警劉巖顾画,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異匆笤,居然都是意外死亡研侣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)炮捧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)庶诡,“玉大人,你說(shuō)我怎么就攤上這事咆课∧┦模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵书蚪,是天一觀的道長(zhǎng)喇澡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)殊校,這世上最難降的妖魔是什么晴玖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮为流,結(jié)果婚禮上呕屎,老公的妹妹穿的比我還像新娘。我一直安慰自己敬察,他們只是感情好秀睛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著莲祸,像睡著了一般蹂安。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锐帜,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天藤抡,我揣著相機(jī)與錄音,去河邊找鬼抹估。 笑死缠黍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的药蜻。 我是一名探鬼主播瓷式,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼替饿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了贸典?” 一聲冷哼從身側(cè)響起视卢,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎廊驼,沒(méi)想到半個(gè)月后据过,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妒挎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年绳锅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酝掩。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鳞芙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出期虾,到底是詐尸還是另有隱情原朝,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布镶苞,位于F島的核電站喳坠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏茂蚓。R本人自食惡果不足惜丙笋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望煌贴。 院中可真熱鬧,春花似錦锥忿、人聲如沸牛郑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)淹朋。三九已至,卻和暖如春钉答,著一層夾襖步出監(jiān)牢的瞬間础芍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工数尿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仑性,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓眶痰,卻偏偏與公主長(zhǎng)得像劳曹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子你画,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容