Lambda表達(dá)式

Java 中的 Lambda 表達(dá)式通常使用 (argument) -> (body) 語法書寫,例如:
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }

以下是一些 Lambda 表達(dá)式的例子:

(int a, int b) -> {  return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };

Lambda 表達(dá)式的結(jié)構(gòu)

讓我們了解一下 Lambda 表達(dá)式的結(jié)構(gòu)法梯。

  • 一個(gè) Lambda 表達(dá)式可以有零個(gè)或多個(gè)參數(shù)
  • 參數(shù)的類型既可以明確聲明昧穿,也可以根據(jù)上下文來推斷镣屹。例如:(int a)與(a)效果相同
  • 所有參數(shù)需包含在圓括號(hào)內(nèi)尽棕,參數(shù)之間用逗號(hào)相隔戚哎。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
  • 空?qǐng)A括號(hào)代表參數(shù)集為空项栏。例如:() -> 42
  • 當(dāng)只有一個(gè)參數(shù)浦辨,且其類型可推導(dǎo)時(shí),圓括號(hào)()可省略沼沈。例如:a -> return a*a
  • Lambda 表達(dá)式的主體可包含零條或多條語句
  • 如果 Lambda 表達(dá)式的主體只有一條語句流酬,花括號(hào){}可省略。匿名函數(shù)的返回類型與該主體表達(dá)式一致
  • 如果 Lambda 表達(dá)式的主體包含一條以上語句列另,則表達(dá)式必須包含在花括號(hào){}中(形成代碼塊)芽腾。匿名函數(shù)的返回類型與代碼塊的返回類型一致,若沒有返回則為空

什么是函數(shù)式接口

在 Java 中页衙,Marker(標(biāo)記)類型的接口是一種沒有方法或?qū)傩月暶鞯慕涌谔希?jiǎn)單地說,marker 接口是空接口店乐。相似地艰躺,函數(shù)式接口是只包含一個(gè)抽象方法聲明的接口。

java.lang.Runnable 就是一種函數(shù)式接口眨八,在 Runnable 接口中只聲明了一個(gè)方法 void run()腺兴,相似地,ActionListener 接口也是一種函數(shù)式接口廉侧,我們使用匿名內(nèi)部類來實(shí)例化函數(shù)式接口的對(duì)象页响,有了 Lambda 表達(dá)式篓足,這一方式可以得到簡(jiǎn)化。

每個(gè) Lambda 表達(dá)式都能隱式地賦值給函數(shù)式接口拘泞,例如纷纫,我們可以通過 Lambda 表達(dá)式創(chuàng)建 Runnable 接口的引用。

Runnable r = () -> System.out.println("hello world");

當(dāng)不指明函數(shù)式接口時(shí)陪腌,編譯器會(huì)自動(dòng)解釋這種轉(zhuǎn)化:

new Thread(
   () -> System.out.println("hello world")
).start();

因此辱魁,在上面的代碼中,編譯器會(huì)自動(dòng)推斷:根據(jù)線程類的構(gòu)造函數(shù)簽名 public Thread(Runnable r) { }诗鸭,將該 Lambda 表達(dá)式賦給 Runnable 接口染簇。

以下是一些 Lambda 表達(dá)式及其函數(shù)式接口:

Consumer<Integer>  c = (int x) -> { System.out.println(x) };

BiConsumer<Integer, String> b = (Integer x, String y) -> System.out.println(x + " : " + y);

Predicate<String> p = (String s) -> { s == null };

@FunctionalInterface

是 Java 8 新加入的一種接口,用于指明該接口類型聲明是根據(jù) Java 語言規(guī)范定義的函數(shù)式接口强岸。Java 8 還聲明了一些 Lambda 表達(dá)式可以使用的函數(shù)式接口锻弓,當(dāng)你注釋的接口不是有效的函數(shù)式接口時(shí),可以使用 @FunctionalInterface 解決編譯層面的錯(cuò)誤蝌箍。

以下是一種自定義的函數(shù)式接口: @FunctionalInterface public interface WorkerInterface {

public void doSomeWork();
}

根據(jù)定義青灼,函數(shù)式接口只能有一個(gè)抽象方法,如果你嘗試添加第二個(gè)抽象方法妓盲,將拋出編譯時(shí)錯(cuò)誤杂拨。例如:

@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

    public void doSomeMoreWork();

}

錯(cuò)誤:

Unexpected @FunctionalInterface annotation 
    @FunctionalInterface ^ WorkerInterface is not a functional interface multiple 
    non-overriding abstract methods found in interface WorkerInterface 1 error

Lambda 表達(dá)式舉例

線程可以通過以下方法初始化:

//舊方法:
new Thread(new Runnable() {
@Override
public void run() {
    System.out.println("Hello from thread");
}
}).start();

//新方法:
new Thread(
() -> System.out.println("Hello from thread")
).start();

事件處理可以使用 Java 8 的 Lambda 表達(dá)式解決。下面的代碼中悯衬,我們將使用新舊兩種方式向一個(gè) UI 組件添加 ActionListener:

 //Old way:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
    System.out.println("The button was clicked using old fashion code!");
}
});

//New way:
button.addActionListener( (e) -> {
    System.out.println("The button was clicked. From Lambda expressions !");
});

以下代碼的作用是打印出給定數(shù)組中的所有元素弹沽。注意,使用 Lambda 表達(dá)式的方法不止一種筋粗。在下面的例子中策橘,我們先是用常用的箭頭語法創(chuàng)建 Lambda 表達(dá)式,之后娜亿,使用 Java 8 全新的雙冒號(hào)(::)操作符將一個(gè)常規(guī)方法轉(zhuǎn)化為 Lambda 表達(dá)式:

//Old way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
   System.out.println(n);
}

//New way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));


//or we can use :: double colon operator in Java 8
list.forEach(System.out::println);

在下面的例子中丽已,我們使用斷言(Predicate)函數(shù)式接口創(chuàng)建一個(gè)測(cè)試,并打印所有通過測(cè)試的元素买决,這樣促脉,你就可以使用 Lambda 表達(dá)式規(guī)定一些邏輯,并以此為基礎(chǔ)有所作為:

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Main {

public static void main(String [] a)  {

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

    System.out.println("Print all numbers:");
    evaluate(list, (n)->true);

    System.out.println("Print no numbers:");
    evaluate(list, (n)->false);

    System.out.println("Print even numbers:");
    evaluate(list, (n)-> n%2 == 0 );

    System.out.println("Print odd numbers:");
    evaluate(list, (n)-> n%2 == 1 );

    System.out.println("Print numbers greater than 5:");
    evaluate(list, (n)-> n > 5 );

}

public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
    for(Integer n: list)  {
        if(predicate.test(n)) {
            System.out.println(n + " ");
        }
    }
}

}   

下面的例子使用 Lambda 表達(dá)式打印數(shù)值中每個(gè)元素的平方策州,注意我們使用了 .stream() 方法將常規(guī)數(shù)組轉(zhuǎn)化為流。Java 8 增加了一些超棒的流 APIs宫仗。

java.util.stream.Stream

接口包含許多有用的方法够挂,能結(jié)合 Lambda 表達(dá)式產(chǎn)生神奇的效果。我們將 Lambda 表達(dá)式

x -> x*x

傳給 map() 方法藕夫,該方法會(huì)作用于流中的所有元素孽糖。之后枯冈,我們使用 forEach 方法打印數(shù)據(jù)中的所有元素:

//Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
for(Integer n : list) {
    int x = n * n;
    System.out.println(x);
}

//New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
list.stream().map((x) -> x*x).forEach(System.out::println);

下面的例子會(huì)計(jì)算給定數(shù)值中每個(gè)元素平方后的總和。請(qǐng)注意办悟,Lambda 表達(dá)式只用一條語句就能達(dá)到此功能尘奏,這也是 MapReduce 的一個(gè)初級(jí)例子。我們使用 map() 給每個(gè)元素求平方病蛉,再使用 reduce() 將所有元素計(jì)入一個(gè)數(shù)值:

//Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = 0;
for(Integer n : list) {
    int x = n * n;
    sum = sum + x;
}
System.out.println(sum);

//New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sum);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炫加,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铺然,更是在濱河造成了極大的恐慌俗孝,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魄健,死亡現(xiàn)場(chǎng)離奇詭異赋铝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沽瘦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門革骨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人析恋,你說我怎么就攤上這事良哲。” “怎么了绿满?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵臂外,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我喇颁,道長(zhǎng)漏健,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任橘霎,我火速辦了婚禮蔫浆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘姐叁。我一直安慰自己瓦盛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布外潜。 她就那樣靜靜地躺著原环,像睡著了一般。 火紅的嫁衣襯著肌膚如雪处窥。 梳的紋絲不亂的頭發(fā)上嘱吗,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音滔驾,去河邊找鬼谒麦。 笑死俄讹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绕德。 我是一名探鬼主播患膛,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼耻蛇!你這毒婦竟也來了踪蹬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤城丧,失蹤者是張志新(化名)和其女友劉穎延曙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亡哄,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枝缔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚊惯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愿卸。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖截型,靈堂內(nèi)的尸體忽然破棺而出趴荸,到底是詐尸還是另有隱情,我是刑警寧澤宦焦,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布发钝,位于F島的核電站,受9級(jí)特大地震影響波闹,放射性物質(zhì)發(fā)生泄漏酝豪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一精堕、第九天 我趴在偏房一處隱蔽的房頂上張望孵淘。 院中可真熱鬧,春花似錦歹篓、人聲如沸瘫证。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)背捌。三九已至,卻和暖如春洞斯,著一層夾襖步出監(jiān)牢的瞬間载萌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扭仁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓厅翔,卻偏偏與公主長(zhǎng)得像乖坠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刀闷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 摘要:此篇文章主要介紹 Java8 Lambda 表達(dá)式產(chǎn)生的背景和用法熊泵,以及 Lambda 表達(dá)式與匿名類的不同...
    OneAPM閱讀 2,071評(píng)論 0 26
  • 簡(jiǎn)介 概念 Lambda 表達(dá)式可以理解為簡(jiǎn)潔地表示可傳遞的匿名函數(shù)的一種方式:它沒有名稱,但它有參數(shù)列表甸昏、函數(shù)主...
    劉滌生閱讀 3,193評(píng)論 5 18
  • 聲明:本文翻譯自The Java? Tutorials(官方文檔) 簡(jiǎn)述 匿名類有一個(gè)問題顽分,如果匿名類的實(shí)現(xiàn)非常簡(jiǎn)...
    猴子小皮球閱讀 4,631評(píng)論 0 9
  • 老公健身已整整五個(gè)月,幾乎每天運(yùn)動(dòng)施蜜。體重從五個(gè)月前69.8公斤到現(xiàn)在只有59.9公斤卒蘸。瘦了十公斤!他還改變了飲食習(xí)...
    珍妮LEE閱讀 649評(píng)論 2 2
  • “上行之詩(shī)”也是“朝拜者之詩(shī)”翻默,當(dāng)時(shí)他們?nèi)ナサ畛荩磕暧袔讉€(gè)大的節(jié)期是一定要上耶路撒冷過的)缸沃,由于耶路撒冷的地理...
    linlydtc閱讀 10,522評(píng)論 0 1