樂字節(jié)-Java8新特性-Lambda表達(dá)式

上一篇文章我們了解了Java8新特性-接口默認(rèn)方法蜕衡,接下來(lái)我們聊一聊Java8新特性之Lambda表達(dá)式缚甩。

Lambda表達(dá)式(也稱為閉包),它允許我們將函數(shù)當(dāng)成參數(shù)傳遞給某個(gè)方法,或者把代碼本身當(dāng)作數(shù)據(jù)處理吴侦。很多語(yǔ)言(Groovy挖胃、Scala等)從設(shè)計(jì)之初就支持Lambda表達(dá)式杂靶。但是java中使用的是?匿名內(nèi)部類代替

最后借助強(qiáng)大的社區(qū)力量酱鸭,找了一個(gè)折中的Lambda實(shí)現(xiàn)方案吗垮,可以實(shí)現(xiàn)簡(jiǎn)潔而緊湊的語(yǔ)言結(jié)構(gòu)。

1凛辣、匿名內(nèi)部類到Lambda的演化

匿名內(nèi)部類抱既,即一個(gè)沒有名字的,存在于一個(gè)類或方法內(nèi)部的類扁誓。當(dāng)我們需要用某個(gè)類且只需要用一次防泵,創(chuàng)建和使用和二為一時(shí),我們可以選擇匿名內(nèi)部類蝗敢,省掉我們定義類的步驟捷泞。

匿名內(nèi)部類會(huì)隱士的繼承一個(gè)類或?qū)崿F(xiàn)一個(gè)接口,或者說(shuō)匿名內(nèi)部類是一個(gè)繼承了該類或者實(shí)現(xiàn)了該接口的子類匿名對(duì)象寿谴。下面看一個(gè)匿名內(nèi)部類的例子:

測(cè)試類中調(diào)用方法

package com.lotbyte.main;

/*

? ? 定義和使用匿名內(nèi)部類

*/

public class NoNameClass {

? ? public static void main(String[] args) {

? ? ? ? Model m = new Model(){

? ? ? ? ? ? @Override

? ? ? ? ? ? public void func() {

? ? ? ? ? ? ? ? System.out.println("方法的實(shí)現(xiàn)");

? ? ? ? ? ? }

? ? ? ? };

? ? ? ? m.func();

? ? }

}

// 需要被實(shí)現(xiàn)的接口

interface Model{

? ? void func();

}

2锁右、Lambda快速使用

從某種意義上來(lái)說(shuō),Lambda表達(dá)式可以看作是匿名內(nèi)部類對(duì)象的簡(jiǎn)寫形式。最簡(jiǎn)單的Lambda表達(dá)式可以由 用逗號(hào)分隔的參數(shù)列表咏瑟、->符號(hào)和語(yǔ)句塊組成拂到。

注意:此時(shí)匿名內(nèi)部類只能實(shí)現(xiàn)接口,不能是繼承抽象類

例如將上面的例子做一個(gè)簡(jiǎn)化码泞,使用Lambda的形式如下:

public class NonameClassForLambda {

? ? public static void main(String[] args) {

? ? ? ? // Lambda方式簡(jiǎn)寫兄旬,方法實(shí)現(xiàn)可以很簡(jiǎn)單

? ? ? ? Model1 md = ()-> System.out.println("hello");

? ? ? ? md.func();


? ? ? ? // 也可以是比較復(fù)雜的操作

? ? ? ? md = () -> {

? ? ? ? ? ? for (int i = 1; i <=5; i++) {

? ? ? ? ? ? ? ? System.out.println(i);

? ? ? ? ? ? }

? ? ? ? };

? ? ? ? md.func();

? ? }

}

// 接口

interface Model1{

? ? void func();

}


以上是一個(gè)簡(jiǎn)單的Lambda的書寫形式,()中是形參列表余寥,沒有則為空括號(hào)领铐,?->為語(yǔ)法格式,之后則為方法的實(shí)現(xiàn)(一條語(yǔ)句可以直接書寫宋舷,當(dāng)有多條語(yǔ)句時(shí)绪撵,需要使用{}進(jìn)行包裹)嚣崭。從這可以看出在接口中必須只能存在一個(gè)抽象方法淫奔。

注意:Lambda中必須有個(gè)接口


3、Lambda的形式

使用Lambda時(shí)偏序,實(shí)現(xiàn)方法可以有參數(shù)续膳,也可以有返回值改艇,如果沒指定參數(shù)類型,則由編譯器自行推斷得出坟岔。

3.1谒兄、 無(wú)參帶返回值

生成[1,10]之間的任意整數(shù)

說(shuō)明:Lambda的改寫需要有對(duì)應(yīng)的抽象方法,當(dāng)沒有參數(shù)時(shí)需要使用()占位社付,當(dāng)表達(dá)式只有一行代碼時(shí)承疲,可以省略return和{}

interface Model2{

? ? int func();

}

Model2 md2 = () -> {return (int)(Math.random()*10+1)};

以上的Lambda等價(jià)于:

Model2md2=()->(int)(Math.random()*10+1);

3.2 、帶參帶返回值

返回一個(gè)對(duì)數(shù)字描述的字符串

interface Model3{

? ? String func(int a);

}

Model3 md3 = (int a) -> {

? ? return "This is a number " + a;

};

說(shuō)明:形參寫在()內(nèi)即可鸥咖,參數(shù)的類型可以省略燕鸽,此時(shí)將由編譯器自行推斷得出,同時(shí)還可以省略()

md3=a->"This is a number "+a;

省略了參數(shù)類型啼辣,小括號(hào)啊研,同時(shí)連帶實(shí)現(xiàn)體的括號(hào)和return都省了。

3.3 鸥拧、帶多個(gè)參數(shù)

根據(jù)輸入的運(yùn)算符計(jì)算兩個(gè)數(shù)的運(yùn)算党远,并返回結(jié)果:

interface Model4{

? ? String func(int a, int b, String oper);

}

Model4 md4 = (a, b, s) -> {

? ? ? String res = "";

? ? ? if("+".equals(s)){

? ? ? ? ? ? res = ( a+b ) + "";

? ? ? }else if("-".equals(s)){

? ? ? ? ? ? res = ( a-b ) + "";

? ? ? }else if("*".equals(s)){

? ? ? ? ? ? res = ( a*b ) + "";

? ? ? }else if("/".equals(s)){

? ? ? ? ? ? res = ( a/b ) + ""; // 暫不考慮除0的情況

? ? ? }else{

? ? ? ? ? ? res =? "操作有失誤";

? ? ? }

? ? ? return res;

};

System.out.println(md4.func(1,1,"+"));

以上例子為多個(gè)參數(shù)的Lambda表達(dá)式,其中省略掉了每一個(gè)參數(shù)的類型富弦,編譯器自動(dòng)推斷沟娱。多條語(yǔ)句時(shí)實(shí)現(xiàn)體的{}不能省。

4腕柜、Lambda作為參數(shù)

在jdk8之前济似,接口可以作為方法參數(shù)傳入矫废,執(zhí)行時(shí)必須提供接口實(shí)現(xiàn)類的實(shí)例。從java8開始砰蠢,Lambda可以作為接口方法實(shí)現(xiàn)蓖扑,當(dāng)作參數(shù)傳入,無(wú)論從形式上還是實(shí)際上都省去了對(duì)象的創(chuàng)建娩脾。使代碼更加的緊湊簡(jiǎn)單高效赵誓。

使用Lambda表達(dá)式需要有以下幾步:

? 1、定義接口柿赊,抽象方法的模板;

? 2幻枉、在某方法中需要接口作為參數(shù)碰声;

? 3、調(diào)用方法時(shí)需要將抽象方法實(shí)現(xiàn)(此時(shí)我們使用Lambda表達(dá)式)并傳入即可熬甫。


4.1胰挑、定義接口

在接口中,必須有且僅有一個(gè)抽象方法椿肩,以確定Lambda模板

// 無(wú)參無(wú)返回值的方法

interface LambdaInterface1{

? ? void printString();

}

// 帶參無(wú)返回值的方法

interface? LambdaInterface2{

? ? void printString(String str);

}

4.2瞻颂、定義方法接收參數(shù)

在某方法中需要使用接口作為參數(shù)

// 無(wú)參

public static void testLambda(LambdaInterface1 lam1){

? ? lam1.printString();

}

// 帶參

public static void testLambda2(String s,LambdaInterface2 lam2){

? ? lam2.printString(s);

}

4.3、Lambda實(shí)現(xiàn)

使用方法時(shí)需要用Lambda將抽象方法實(shí)現(xiàn)

使用方法時(shí)需要用Lambda將抽象方法實(shí)現(xiàn)

// 無(wú)參Lambda作為參數(shù)

testLambda(()->{

? ? System.out.println("可以簡(jiǎn)單郑象,可以復(fù)雜");

});

// 帶參Lambda作為參數(shù)

testLambdaParam("hello",(a)->{

? ? System.out.println(a);

});

通過以上三步贡这,能夠完整地展示Lambda從和演變而來(lái)。此后在使用時(shí)厂榛,jdk中已經(jīng)提供很多場(chǎng)景了盖矫,即前兩部已經(jīng)完成,我們更多的是實(shí)現(xiàn)第三步即可击奶。

5辈双、forEach展示Lambda

例如以ArrayList的遍歷為例子,分析Lambda的使用方式柜砾。

public static void main(String[] args) {

? ? List<String> strs = new ArrayList<String>(){

? ? ? ? {

? ? ? ? ? ? add("aaa");

? ? ? ? ? ? add("bbb");

? ? ? ? ? ? add("ccc");

? ? ? ? }

? ? };

? ? strs.forEach((str)-> System.out.println(str));

}

下面看看forEach的源碼湃望,定義中使用了接口Consumer作為參數(shù),并調(diào)用了其方法:


Consumer中的抽象方法只有accept一個(gè)


通過在forEach方法中調(diào)用Consumer的accept方法痰驱,并將每一個(gè)元素作為參數(shù)傳入证芭,使得accept方法可以對(duì)每一個(gè)元素進(jìn)行操作,當(dāng)我們使用Lambda實(shí)現(xiàn)accept時(shí)就變成了我們自己對(duì)每一個(gè)元素的處理了萄唇。我們只負(fù)責(zé)處理即可檩帐。

6、Lambda中使用變量

? 在Lambda中可以定義自己的局部變量另萤,也可以使用外層方法的局部變量湃密,還可以使用屬性诅挑。這一點(diǎn)也不難理解,既然是一個(gè)方法的實(shí)現(xiàn)泛源,只寫了一個(gè)代碼塊拔妥,那么使用本身所屬方法的局部變量和類的屬性也并不過分。

public static void main(String[] args) {

? ? List<String> strs = new ArrayList<String>(){

? ? ? ? {

? ? ? ? ? ? add("aaa");

? ? ? ? ? ? add("bbb");

? ? ? ? ? ? add("ccc");

? ? ? ? }

? ? };

? ? int j = 1;

? ? strs.forEach((str)->{

? ? ? ? int i = 0;

? ? ? ? System.out.println(str + "? " + i + "? " + j);

? ? });

}

注意:此時(shí)外部局部變量將自動(dòng)變?yōu)閒inal

7达箍、Lambda作為方法返回值

例子:返回判斷字符串是否為空

public class Demo004_2 {

? ? public static void main(String[] args) {

? ? ? ? System.out.println(testLambda().isEmpty("string"));

? ? }

? ? // 判斷字符串是否為空

? ? public static AssertEmpty testLambda(){

? ? ? ? return (n)-> null==n||n.trim().isEmpty(n);

? ? }

}

interface AssertEmpty{

? ? boolean isEmpty(String str);

}

今天關(guān)于Java8新特性-Lambda表達(dá)式就講到這里了没龙,接下來(lái)我會(huì)繼續(xù)講述Java8新特性之函數(shù)式接口。敬請(qǐng)繼續(xù)關(guān)注缎玫!歡迎留言評(píng)論硬纤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赃磨,隨后出現(xiàn)的幾起案子筝家,更是在濱河造成了極大的恐慌,老刑警劉巖邻辉,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溪王,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡值骇,警方通過查閱死者的電腦和手機(jī)莹菱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吱瘩,“玉大人道伟,你說(shuō)我怎么就攤上這事〗寥梗” “怎么了皱卓?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)部逮。 經(jīng)常有香客問我娜汁,道長(zhǎng),這世上最難降的妖魔是什么兄朋? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任掐禁,我火速辦了婚禮,結(jié)果婚禮上颅和,老公的妹妹穿的比我還像新娘傅事。我一直安慰自己,他們只是感情好峡扩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布蹭越。 她就那樣靜靜地躺著,像睡著了一般教届。 火紅的嫁衣襯著肌膚如雪响鹃。 梳的紋絲不亂的頭發(fā)上驾霜,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音买置,去河邊找鬼粪糙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛忿项,可吹牛的內(nèi)容都是我干的蓉冈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼轩触,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寞酿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起脱柱,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤熟嫩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后褐捻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椅邓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年柠逞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片景馁。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡板壮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出合住,到底是詐尸還是另有隱情绰精,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布透葛,位于F島的核電站笨使,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏僚害。R本人自食惡果不足惜硫椰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萨蚕。 院中可真熱鬧靶草,春花似錦、人聲如沸岳遥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浩蓉。三九已至派继,卻和暖如春宾袜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背互艾。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工试和, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纫普。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓阅悍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親昨稼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子节视,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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

  • Java 8自Java 5(發(fā)行于2004)以來(lái)最具革命性的版本。Java 8 為Java語(yǔ)言假栓、編譯器寻行、類庫(kù)、開發(fā)...
    誰(shuí)在烽煙彼岸閱讀 888評(píng)論 0 4
  • Java 8自Java 5(發(fā)行于2004)以來(lái)最具革命性的版本匾荆。Java 8 為Java語(yǔ)言拌蜘、編譯器、類庫(kù)牙丽、開發(fā)...
    huoyl0410閱讀 632評(píng)論 1 2
  • java8新特性 原創(chuàng)者:文思 一简卧、特性簡(jiǎn)介 速度更快 代碼更少,增加了Lambda 強(qiáng)大的Stream API ...
    文思li閱讀 3,050評(píng)論 1 1
  • lambda表達(dá)式(又被成為“閉包”或“匿名方法”)方法引用和構(gòu)造方法引用擴(kuò)展的目標(biāo)類型和類型推導(dǎo)接口中的默認(rèn)方法...
    183207efd207閱讀 1,483評(píng)論 0 5
  • 2018年5月11日早晨烤芦,朋友在微信群里面發(fā)出了如下消息举娩。 果不其然,隨后幣值大幅下跌构罗。第二天也就是5...
    只想飛的豬閱讀 568評(píng)論 0 1