Java lambda表達(dá)式

什么是lambda表達(dá)式

看看lambda表達(dá)式在其他語(yǔ)言中怎么使用的:

在python中有l(wèi)ambda表達(dá)式带污,在python中可以使用它定義匿名方法哼凯,并賦值給一個(gè)變量锉屈,然后那個(gè)變量就成為了一個(gè)方法继阻,比如

f = lambda x:  (x + 1 ) if x > 100 else x - 1
# 相當(dāng)于
def f(x):
    return (x + 1 ) if x > 100 else x - 1;

或者把lambda表達(dá)式傳給一個(gè)方法露筒,例如:

def m(fun,x):
    fun(x)
m(lambda x: print(x),1000)

由上面的示例可以看出來(lái)呐伞,lambda表達(dá)式是一段可執(zhí)行的代碼塊,可傳入方法內(nèi)執(zhí)行慎式,且可以賦給任意變量由變量執(zhí)行伶氢。
這其實(shí)也是支持函數(shù)式編程的特征踩娘,一段代碼塊可以在任何場(chǎng)所執(zhí)行惋鹅,不像java吁讨,需要借助對(duì)象這個(gè)承載來(lái)執(zhí)行代碼塊扎唾。從python的執(zhí)行方式就可以看出來(lái)瑞妇,
我們可以在一個(gè)py文件中輸入print 'hello world',然后就可以直接執(zhí)行輸出做瞪;但是在java中妹田,你需要先創(chuàng)建一個(gè)類(lèi)带膀,然后創(chuàng)建main方法扇救,在main方法里面執(zhí)行System.out.println("hello world");
可以看出來(lái)刑枝,支持函數(shù)式編程能夠減少很多的冗余代碼,但是也因?yàn)殪`活性使得代碼的風(fēng)格十分多變導(dǎo)致代碼不好維護(hù)迅腔。
Java引入lambda表達(dá)式的目的装畅,自然是想引入函數(shù)式編程的優(yōu)點(diǎn),讓代碼簡(jiǎn)潔沧烈,這也是lambda表達(dá)式的作用掠兄。

在java中怎么使用lambda表達(dá)式

既然知道了什么是lambda表達(dá)式,那么再來(lái)了解一下再Java中使用這種語(yǔ)言特性锌雀,有哪些方式又有那些限制和注意事項(xiàng)蚂夕。

函數(shù)式接口

在Java中,lambda是基于函數(shù)式接口的腋逆,也可以理解成它是替換函數(shù)式接口的實(shí)例的匿名對(duì)象婿牍,且它只能轉(zhuǎn)換成函數(shù)式接口。
那么什么是函數(shù)式接口呢惩歉?只有一個(gè)抽象方法的接口等脂,只能有一個(gè)抽象接口俏蛮,但是接口是可以包含default方法的(Java 8特性),如下的接口就是合法的:

@FunctionalInterface
interface FuncInter {
    void test();

    default void testdefault() {
        System.out.println("hello default");
    }
    // void test2(); error it is not a Functional interface
}

@FunctionalInterface
interface FuncInter2 {
    void test(String x);
}

@FunctionalInterface是一個(gè)標(biāo)識(shí)注解上遥,表明本接口只有一個(gè)抽象方法搏屑,如果再次添加抽象方法,會(huì)在編譯期報(bào)錯(cuò)粉楚,加上此注解可以防止誤加抽象方法睬棚。

函數(shù)式接口有了,怎么用呢解幼,先看下在java8 以前抑党,想要傳入一段代碼塊是怎么做的。

    public static void main(String[] args) {
        // 匿名類(lèi)的方法
        FuncInter2 f = new FuncInter2() {

            @Override
            public void test(String x) {
                // TODO Auto-generated method stub

            }

        };
        f.test("hello");
    }

如果不用匿名類(lèi)撵摆,就需要?jiǎng)?chuàng)建一個(gè)類(lèi)實(shí)現(xiàn)接口底靠,再創(chuàng)建接口實(shí)例,最后調(diào)用test方法特铝;

試用lambda表達(dá)式

既然說(shuō)lambda表達(dá)式是用來(lái)替換函數(shù)式接口的暑中,使用lambda的方法應(yīng)該就可以減少相關(guān)代碼的編寫(xiě):

@Test
    public void testLambdasyntax() {

        // lambda表達(dá)式是用來(lái)替換函數(shù)式接口的(匿名)實(shí)例
        /*
         * 無(wú)參抽象方法
         */
        // 1. 單行語(yǔ)句
        FuncInter fi = () -> System.out.println("hello");
        fi.test();
        // 2. 多行語(yǔ)句使用{}包圍
        fi = () -> {
            // TODO
            System.out.println("line 1");
            System.out.println("line 2");
        };
        fi.test();
        /*
         * 有參抽象方法
         */
        FuncInter2 fi2 = (String a) -> System.out.println(a);
        fi2.test("www");
        // 可以推斷參數(shù)類(lèi)型可以不寫(xiě)類(lèi)型
        fi2 = (a) -> System.out.println("no type " + a);
        fi2.test("hello ");
        // 單個(gè)參數(shù),且參數(shù)類(lèi)型可以推斷鲫剿,可以不加括號(hào)
        fi2 = a -> System.out.println("no parentheses " + a);
        fi2.test("hello ");
    }

    /**
     * 把lambda傳給方法 </br>
     * 實(shí)際上就是把函數(shù)式接口的匿名對(duì)象傳給方法 </br>
     * 可以理解成把函數(shù)傳遞給方法鳄逾,但是在java里面實(shí)際上還是基于對(duì)象
     */
    @Test
    public void deliverToMethod() {
        // 定義一個(gè)局部類(lèi)
        class MyClassNeedInterface {
            FuncInter fi = null;

            MyClassNeedInterface(FuncInter fi) {
                this.fi = fi;
            }

            void doSomeThing() {
                fi.test();
            }

            void doSomeThing(FuncInter2 fi, String x) {
                fi.test(x);
            }
        }
        MyClassNeedInterface c = new MyClassNeedInterface(() -> System.out.println("This is from a lambda expression"));
        c.doSomeThing();
        String x = "a string ";
        // 等價(jià)于 c.doSomeThing(a->System.out.println(a), x);
        c.doSomeThing(System.out::println, x);
        c.doSomeThing(a -> System.out.println(a), x);
    }

}

確實(shí)簡(jiǎn)潔了很多×榱可以發(fā)現(xiàn)java中一個(gè)lambda表達(dá)式的形式是 參數(shù)雕凹、箭頭、表達(dá)式政冻,且可以根據(jù)情況省略括號(hào)或者參數(shù)類(lèi)型枚抵,定義出來(lái)的表達(dá)式相當(dāng)于一個(gè)接口的實(shí)例對(duì)象。
箭頭后面的表達(dá)式如果是多行代碼明场,使用花括號(hào)括起來(lái)汽摹。
實(shí)際上lambda表達(dá)式的用法,也就限于此類(lèi)情況(替代函數(shù)式接口的匿名實(shí)例)苦锨。

方法引用

在示例deliverToMethod中有System.out::println這種形式的使用逼泣,是引用了已經(jīng)存在的方法來(lái)填充接口的抽象方法,它支持三種形式:

  • instance::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod 此種方法的調(diào)用 第一個(gè)參數(shù)是實(shí)例方法的調(diào)用者(方法的目標(biāo))舟舒。

構(gòu)造器引用

和上節(jié)的方法引用類(lèi)似拉庶,只是引用的方法名是new。

閉包

閉包(closure)是計(jì)算機(jī)編程領(lǐng)域的專(zhuān)業(yè)名詞魏蔗,指可以包含自由(未綁定到特定對(duì)象)變量的代碼塊砍的,子函數(shù)可以使用父函數(shù)中的局部變量。

lambda表達(dá)式使得java擁有了閉包這個(gè)特性莺治。 簡(jiǎn)單來(lái)說(shuō)廓鞠,閉包是有數(shù)據(jù)的行為(函數(shù)、方法),是可以讀取其他函數(shù)內(nèi)部變量的函數(shù)谣旁。
lambda表達(dá)式具有代碼塊床佳,那么自由變量是什么?所謂自由變量榄审,是未綁定到特定對(duì)象的變量砌们,那么外部的局部變量肯定是自由變量;
子函數(shù)可以使用父函數(shù)中的局部變量搁进,也就是代碼塊可以訪問(wèn)外圍的局部變量浪感,還要能夠攜帶出去。

@FunctionalInterface
interface Closure {
    int test(int a);
}
    @Test
    public void testClosure() {
        final int a = 100; // 這里的final可以不加但是得建立在后面不會(huì)修改的前提上饼问,所以還是建議加上;
        Closure ci = (b) -> {
            System.out.println("I catch a int value of a :" + a);
            return (a + b);
        };
        // a month later
        int v = ci.test(1);
        System.out.println(v);
    }

在java中莱革,在lambda中訪問(wèn)的外部局部變量峻堰,必須是final變量,即引用不可修改盅视,如果是基本類(lèi)型捐名,必須是常量。
另外有一個(gè)很重要的規(guī)則闹击,lambda表達(dá)式的體和使用這個(gè)表達(dá)式的塊具有同一個(gè)作用域镶蹋。所以同名變量會(huì)命名沖突
如:

@Test
    public void testSocpe() {
        int a = 1000;
        Closure closure = a -> a + 100; // ERROR
    }
    @Test
    public void testSocpe() {
        int b = 1000;
        Closure c = a -> this.add100(a);//this的作用域是在testScope方法里面
        System.out.println(c.test(b));// 1100

    }

    private int add100(int a) {
        return a + 100;
    }

什么時(shí)候使用lambda表達(dá)式

lambda表達(dá)式定義的可執(zhí)行代碼塊,如果是需要立即執(zhí)行的赏半,可以直接寫(xiě)在執(zhí)行方法里面梅忌,何必繞個(gè)圈子去調(diào)用接口的方法呢。所以lambda表達(dá)式的使用場(chǎng)景是除破,暫時(shí)不要執(zhí)行的代碼塊牧氮,在未來(lái)因?yàn)槟硞€(gè)事件觸發(fā)而執(zhí)行,所以重點(diǎn)在于延遲執(zhí)行瑰枫。

jdk提供了一系列的函數(shù)式接口踱葛,涵蓋很多使用場(chǎng)景。常用的有:

接口 抽象方法 參數(shù)類(lèi)型 返回值類(lèi)型
Runnable run - void
Supplier<T> get - T
Consumer<T> accept T void
Predicate<T> test T boolean
圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App
  • 參考文獻(xiàn)
    [Java核心技術(shù) 卷I 第十版]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末光坝,一起剝皮案震驚了整個(gè)濱河市尸诽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盯另,老刑警劉巖性含,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鸳惯,居然都是意外死亡商蕴,警方通過(guò)查閱死者的電腦和手機(jī)叠萍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绪商,“玉大人苛谷,你說(shuō)我怎么就攤上這事「裼簦” “怎么了腹殿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)例书。 經(jīng)常有香客問(wèn)我锣尉,道長(zhǎng),這世上最難降的妖魔是什么决采? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任自沧,我火速辦了婚禮,結(jié)果婚禮上织狐,老公的妹妹穿的比我還像新娘暂幼。我一直安慰自己,他們只是感情好移迫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布旺嬉。 她就那樣靜靜地躺著,像睡著了一般厨埋。 火紅的嫁衣襯著肌膚如雪邪媳。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天荡陷,我揣著相機(jī)與錄音雨效,去河邊找鬼。 笑死废赞,一個(gè)胖子當(dāng)著我的面吹牛徽龟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唉地,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼据悔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了耘沼?” 一聲冷哼從身側(cè)響起极颓,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎群嗤,沒(méi)想到半個(gè)月后菠隆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年骇径,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躯肌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡既峡,死狀恐怖羡榴,靈堂內(nèi)的尸體忽然破棺而出碧查,到底是詐尸還是另有隱情运敢,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布忠售,位于F島的核電站传惠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏稻扬。R本人自食惡果不足惜卦方,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泰佳。 院中可真熱鬧盼砍,春花似錦、人聲如沸逝她。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)黔宛。三九已至近刘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臀晃,已是汗流浹背觉渴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留徽惋,地道東北人案淋。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像险绘,于是被迫代替她去往敵國(guó)和親踢京。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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