Java lambda表達(dá)式用法介紹

在本文中惦费,我們將通過示例了解Javalambda表達(dá)式以及l(fā)ambda表達(dá)式在函數(shù)接口、通用函數(shù)接口和流API中的使用。

lambda表達(dá)式是在Java8中首次引入的掀鹅。它的主要目標(biāo)是提高語言的表達(dá)能力揽碘。

但是次屠,在進(jìn)入lambdas之前,我們首先需要了解功能接口雳刺。

什么是Functional Interface劫灶?

如果Java接口包含一個(gè)且僅包含一個(gè)抽象方法,則稱為函數(shù)接口掖桦。只有一種方法指定了接口的預(yù)期用途本昏。

例如,包java.lang中的Runnable接口枪汪;是一個(gè)函數(shù)接口涌穆,因?yàn)樗粯?gòu)成一個(gè)方法,即run()雀久。

示例1:用java定義函數(shù)接口

import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    // the single abstract method
    double getValue();
}

在上面的示例中宿稀,接口MyInterface只有一個(gè)抽象方法getValue()。因此赖捌,它是一個(gè)功能接口祝沸。

這里,我們使用了注釋@functioninterface越庇。注釋強(qiáng)制Java編譯器指示該接口是功能接口罩锐。因此,不允許有多個(gè)抽象方法卤唉。然而涩惑,這不是強(qiáng)制性的。

在Java7中桑驱,函數(shù)接口被視為單一抽象方法或SAM類型竭恬。SAMs通常在Java7中使用匿名類實(shí)現(xiàn)。

示例2:用java中的匿名類實(shí)現(xiàn)SAM

public class FunctionInterfaceTest {
    public static void main(String[] args) {

        // anonymous class
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I just implemented the Runnable Functional Interface.");
            }
        }).start();
    }
}

輸出:

 just implemented the Runnable Functional Interface.

在這里熬的,我們可以將一個(gè)匿名類傳遞給一個(gè)方法萍聊。這有助于在Java7中編寫代碼更少的程序。但是悦析,語法仍然很難寿桨,需要很多額外的代碼行。

Java8進(jìn)一步擴(kuò)展了SAMs的功能。因?yàn)槲覀冎篮瘮?shù)接口只有一個(gè)方法亭螟,所以在將其作為參數(shù)傳遞時(shí)挡鞍,不需要定義該方法的名稱。Lambda表達(dá)式允許我們完全做到這一點(diǎn)预烙。

Lambda表達(dá)式簡介

Lambda表達(dá)式本質(zhì)上是一個(gè)匿名或未命名的方法墨微。lambda表達(dá)式不會(huì)自行執(zhí)行。相反扁掸,它用于實(shí)現(xiàn)由函數(shù)接口定義的方法翘县。

如何在Java中定義lambda表達(dá)式?

下面是如何在Java中定義lambda表達(dá)式谴分。

(parameter list) -> lambda body

使用的新運(yùn)算符(->)稱為箭頭運(yùn)算符或lambda運(yùn)算符锈麸。語法目前可能不清楚。讓我們來探討一些例子牺蹄,

假設(shè)我們有這樣一種方法:

double getPiValue() {
    return 3.1415;
}

我們可以使用lambda表達(dá)式編寫此方法忘伞,如下所示:

() -> 3.1415

這里,該方法沒有任何參數(shù)沙兰。因此氓奈,運(yùn)算符的左側(cè)包含一個(gè)空參數(shù)。右側(cè)是lambda主體鼎天,指定lambda表達(dá)式的操作舀奶。在本例中,它返回值3.1415斋射。

Lambda體的類型

在Java中育勺,lambda主體有兩種類型。

  1. 具有單個(gè)表達(dá)式的主體
() -> System.out.println("Lambdas are great");

這種類型的lambda體稱為表達(dá)式體绩鸣。

  1. 由代碼塊組成的主體怀大。
() -> {
    double pi = 3.1415;
    return pi;
};

這種類型的lambda體稱為塊體纱兑。塊體允許lambda體包含多個(gè)語句呀闻。這些語句包含在大括號(hào)內(nèi),必須在大括號(hào)后添加分號(hào)潜慎。

注意:對(duì)于塊體捡多,如果塊體返回值,則可以使用return語句铐炫。但是垒手,表達(dá)式體不需要返回語句。

示例3:Lambda表達(dá)式

讓我們編寫一個(gè)Java程序倒信,使用lambda表達(dá)式返回Pi的值科贬。

如前所述,lambda表達(dá)式不會(huì)單獨(dú)執(zhí)行。相反榜掌,它形成了由函數(shù)接口定義的抽象方法的實(shí)現(xiàn)优妙。

因此,我們需要首先定義一個(gè)功能接口憎账。

import java.lang.FunctionalInterface;

// this is functional interface
@FunctionalInterface
interface MyInterface{

    // abstract method
    double getPiValue();
}

public class Main {

    public static void main( String[] args ) {

    // declare a reference to MyInterface
    MyInterface ref;
    
    // lambda expression
    ref = () -> 3.1415;
    
    System.out.println("Value of Pi = " + ref.getPiValue());
    } 
}

輸出:

Value of Pi = 3.1415

在上面的例子中套硼,

我們已經(jīng)創(chuàng)建了一個(gè)名為MyInterface的功能接口。它包含一個(gè)名為getPiValue()的抽象方法

在主類中胞皱,我們聲明了對(duì)MyInterface的引用邪意。注意,我們可以聲明接口的引用反砌,但不能實(shí)例化接口雾鬼。就是,

// it will throw an error
MyInterface ref = new myInterface();

// it is valid
MyInterface ref;

然后于颖,我們?yōu)橐弥付艘粋€(gè)lambda表達(dá)式呆贿。

ref = () -> 3.1415;

最后,我們使用引用接口調(diào)用方法getPiValue()

System.out.println("Value of Pi = " + ref.getPiValue());

帶參數(shù)的Lambda表達(dá)式

到目前為止森渐,我們已經(jīng)創(chuàng)建了沒有任何參數(shù)的lambda表達(dá)式做入。但是,與方法類似同衣,lambda表達(dá)式也可以有參數(shù)竟块。例如《求職面試筆試寶典》

(n) -> (n%2)==0

這里,括號(hào)內(nèi)的變量n是傳遞給lambda表達(dá)式的參數(shù)耐齐。lambda主體接受參數(shù)并檢查它是偶數(shù)還是奇數(shù)浪秘。

示例4:使用帶參數(shù)的lambda表達(dá)式

@FunctionalInterface
interface MyInterface {

    // abstract method
    String reverse(String n);
}

public class Main {

    public static void main( String[] args ) {

        // declare a reference to MyInterface
        // assign a lambda expression to the reference
        MyInterface ref = (str) -> {

            String result = "";
            for (int i = str.length()-1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        // call the method of the interface
        System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
    }

}

輸出:

Lambda reversed = adbmaL

通用功能接口

到目前為止,我們使用的函數(shù)接口只接受一種類型的值埠况。例如

@FunctionalInterface
interface MyInterface {
    String reverseString(String n);
}

上面的函數(shù)接口只接受字符串并返回字符串耸携。但是,我們可以使函數(shù)接口通用辕翰,以便接受任何數(shù)據(jù)類型夺衍。如果您不確定泛型,請(qǐng)?jiān)L問Java泛型喜命。

示例5:通用函數(shù)接口和Lambda表達(dá)式

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {

    // generic method
    T func(T t);
}

// GenericLambda.java
public class Main {

    public static void main( String[] args ) {

        // declare a reference to GenericInterface
        // the GenericInterface operates on String data
        // assign a lambda expression to it
        GenericInterface<String> reverse = (str) -> {

            String result = "";
            for (int i = str.length()-1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        System.out.println("Lambda reversed = " + reverse.func("Lambda"));

        // declare another reference to GenericInterface
        // the GenericInterface operates on Integer data
        // assign a lambda expression to it
        GenericInterface<Integer> factorial = (n) -> {

            int result = 1;
            for (int i = 1; i <= n; i++)
            result = i * result;
            return result;
        };

        System.out.println("factorial of 5 = " + factorial.func(5));
    }
}

輸出:

Lambda reversed = adbmaL
factorial of 5 = 120

在上面的示例中沟沙,我們創(chuàng)建了一個(gè)名為GenericInterface的通用函數(shù)接口。它包含一個(gè)名為func()的泛型方法壁榕。

在這里矛紫,在主類中,

  • GenericInterface<String>reverse-創(chuàng)建對(duì)接口的引用牌里。該接口現(xiàn)在對(duì)字符串類型的數(shù)據(jù)進(jìn)行操作颊咬。
  • GenericInterface<Integer>factorial-創(chuàng)建對(duì)接口的引用。在本例中,接口對(duì)整型數(shù)據(jù)進(jìn)行操作喳篇。

Lambda表達(dá)式和StreamAPI

新的java.util.stream包已添加到JDK8中缓呛,它允許java開發(fā)人員執(zhí)行搜索、篩選杭隙、映射哟绊、減少或操作列表等集合。

例如痰憎,我們有一個(gè)數(shù)據(jù)流(在本例中是一個(gè)字符串列表)票髓,其中每個(gè)字符串都是國家名稱和國家地點(diǎn)的組合。現(xiàn)在铣耘,我們可以處理這些數(shù)據(jù)流洽沟,只從尼泊爾檢索地方。

為此蜗细,我們可以通過stream API和Lambda表達(dá)式的組合在stream中執(zhí)行批量操作裆操。

示例6:演示將lambdas與stream API一起使用

import java.util.ArrayList;
import java.util.List;

public class StreamMain {

    // create an object of list using ArrayList
    static List<String> places = new ArrayList<>();

    // preparing our data
    public static List getPlaces(){

        // add places and country to the list
        places.add("Nepal, Kathmandu");
        places.add("Nepal, Pokhara");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");

        return places;
    }

    public static void main( String[] args ) {

        List<String> myPlaces = getPlaces();
        System.out.println("Places from Nepal:");
        
        // Filter places from Nepal
        myPlaces.stream()
                .filter((p) -> p.startsWith("Nepal"))
                .map((p) -> p.toUpperCase())
                .sorted()
                .forEach((p) -> System.out.println(p));
    }

}

輸出:

Places from Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA

在上面的示例中,請(qǐng)注意以下語句:

myPlaces.stream()
        .filter((p) -> p.startsWith("Nepal"))
        .map((p) -> p.toUpperCase())
        .sorted()
        .forEach((p) -> System.out.println(p));

這里炉媒,我們使用流API的filter()踪区、map()forEach()等方法。這些方法可以將lambda表達(dá)式作為輸入吊骤。

我們還可以根據(jù)上面學(xué)習(xí)的語法定義自己的表達(dá)式缎岗。這使我們能夠像上面的示例中所看到的那樣,大幅減少代碼行白粉。

《求職面試筆試寶典》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末传泊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鸭巴,更是在濱河造成了極大的恐慌眷细,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹃祖,死亡現(xiàn)場離奇詭異溪椎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)惯豆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門池磁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奔害,“玉大人楷兽,你說我怎么就攤上這事』伲” “怎么了芯杀?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我揭厚,道長却特,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任筛圆,我火速辦了婚禮裂明,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘太援。我一直安慰自己闽晦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布提岔。 她就那樣靜靜地躺著仙蛉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碱蒙。 梳的紋絲不亂的頭發(fā)上荠瘪,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音赛惩,去河邊找鬼哀墓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛喷兼,可吹牛的內(nèi)容都是我干的麸祷。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼褒搔,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼阶牍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起星瘾,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤走孽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后琳状,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磕瓷,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年念逞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了困食。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翎承,死狀恐怖硕盹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叨咖,我是刑警寧澤瘩例,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布啊胶,位于F島的核電站,受9級(jí)特大地震影響垛贤,放射性物質(zhì)發(fā)生泄漏焰坪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一聘惦、第九天 我趴在偏房一處隱蔽的房頂上張望某饰。 院中可真熱鬧,春花似錦善绎、人聲如沸露乏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘟仿。三九已至,卻和暖如春比勉,著一層夾襖步出監(jiān)牢的瞬間劳较,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工浩聋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留观蜗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓衣洁,卻偏偏與公主長得像墓捻,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坊夫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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