和 Lambda 表達(dá)式 Say Hello
如果用一大段枯燥的文字去解釋一個(gè)我們并不熟悉的概念搔预,我覺(jué)得和看天書(shū)并無(wú)區(qū)別。我之所以選擇學(xué)編程叶组,就是因?yàn)闆](méi)有什么是寫(xiě)段代碼不能搞定的拯田。那么廢話少說(shuō),大家先看看清單一中的代碼甩十。
清單一
public class Calculater {
public static void main(String[] args) {
final int a = 1, b = 2;
int result = add(new IIntegerMath() {
@Override
public int operation() {
return a + b;
}
});
System.out.println(result);
}
public static int add(IIntegerMath iIntegerMath) {
return iIntegerMath.operation();
}
}
interface IIntegerMath {
int operation();
}
看完清單一中的代碼船庇,估計(jì)有人要說(shuō)我了,因?yàn)檫@段代碼在上一篇博客中已經(jīng)出現(xiàn)過(guò)了侣监。但這又何妨鸭轮,通過(guò)一段簡(jiǎn)單的代碼,我們可以挖掘很多知識(shí)橄霉。在清單一代碼的 main 函數(shù)中窃爷,我調(diào)用了 add 函數(shù),并使用了一個(gè)匿名內(nèi)部類作為 add 函數(shù)的參數(shù)姓蜂。匿名內(nèi)部類被設(shè)計(jì)的目的之一就是按厘,方便程序員將代碼作為數(shù)據(jù)傳遞。
現(xiàn)在問(wèn)題來(lái)了钱慢,大家有沒(méi)有覺(jué)得這樣的代碼太過(guò)于冗余了逮京。我們明明只需要 a + b 這一條語(yǔ)句,卻附加了很多其他的代碼(命令式代碼)束莫±撩蓿可能由于大家已經(jīng)習(xí)慣了這樣的寫(xiě)法草描,但 Java8 讓我們可以用更加簡(jiǎn)單的代碼實(shí)現(xiàn)相同的功能。那么策严,我們一起來(lái)看清單二中用** Java8** 實(shí)現(xiàn)地與清單一功能相同的代碼穗慕。
清單二
public class Calculater {
public static void main(String[] args) {
int a = 1, b = 2;
int result = add(() -> a + b);
System.out.println(result);
}
public static int add(IIntegerMath iIntegerMath) {
return iIntegerMath.operation();
}
}
interface IIntegerMath {
int operation();
}
如果有人認(rèn)為清單二中的代碼看著不爽,那么我建議他可以去泡個(gè)澡享钞,然后剪個(gè)頭發(fā)揍诽。其實(shí)清單二中的代碼我已經(jīng)在上篇博客中展示了,但我并沒(méi)有解釋 () -> a + b 是幾個(gè)意思栗竖。
我現(xiàn)在給大家分析下 () -> a + b ,其實(shí)這段代碼就是一個(gè) Lambda 表達(dá)式渠啤,也可以理解為一個(gè)函數(shù)狐肢。-> 將參數(shù)和 Lambda 表達(dá)式的主體分割開(kāi)了,-> 的左邊是參數(shù)所在的位置沥曹,() 表示無(wú)參數(shù)份名;-> 右邊的代碼是 Lambda 表達(dá)式的主體。
即使我們知道了 add 函數(shù)中那段代碼是什么意思妓美,我認(rèn)為有些人對(duì)于在 add 函數(shù)中直接傳入一個(gè) Lambda 表達(dá)式還是難以理解僵腺。那么現(xiàn)在我用另一種方式重寫(xiě)清單二中 main 函數(shù)中的代碼,請(qǐng)看清單三壶栋。
清單三
public static void main(String[] args) {
int a = 1, b = 2;
IIntegerMath integerMath = () -> a + b;
int result = add(integerMath);
System.out.println(result);
}
我相信清單三中的代碼對(duì)于大家來(lái)說(shuō)都很熟悉辰如。當(dāng)你無(wú)法理解使用 Lambda 表達(dá)式作為函數(shù)參數(shù)的用法,你們就將 Lambda 表達(dá)式理解為一個(gè)對(duì)象的引用贵试,雖然按理來(lái)說(shuō)我們不能這么來(lái)理解琉兜。
Lambda 表達(dá)式的多種形式
不帶參數(shù)的 Lambda 表達(dá)式
清單四
public class LambdaLearn {
public static void main(String[] args) {
INoArguments noArguments =
() -> System.out.println("no argument");
}
}
interface INoArguments {
void printOperation();
}
清單四中展示了一個(gè)不帶參數(shù)的 Lambda 表達(dá)式,在 -> 的左邊使用空括號(hào) () 代表沒(méi)有參數(shù)毙玻。
帶一個(gè)參數(shù)的Lambda表達(dá)式
清單五
public class LambdaLearn {
public static void main(String[] args) {
IOneArguments<Integer> oneArguments =
(a) -> a > 0;
}
}
interface IOneArguments<T> {
boolean assertOneNum(T argument);
}
清單五展示了一個(gè)只帶一個(gè)參數(shù)的 Lambda 表達(dá)式豌蟋,因?yàn)橹挥幸粋€(gè)參數(shù),所以參數(shù)可以用括號(hào)包裹起來(lái)桑滩,也可以不用梧疲。
帶多個(gè)參數(shù)的 Lambda 表達(dá)式
清單六
public class LambdaLearn {
public static void main(String[] args) {
IMultiArguments<Integer> multiArguments =
(a, b) -> a + b;
}
}
interface IMultiArguments<T> {
T addOperation(T a, T b);
}
清單六中展示了一個(gè)帶多個(gè)參數(shù)的 Lambda 表達(dá)式。因?yàn)橛卸鄠€(gè)參數(shù)运准,所以需要用括號(hào)將多個(gè)參數(shù)包裹起來(lái)幌氮。
注意:我不能用慣性思維去閱讀清單六中 Lambda 表達(dá)式。該 Lambda 表達(dá)式并不是將兩個(gè)數(shù)字相加戳吝,而是創(chuàng)建了一個(gè)函數(shù)浩销,用來(lái)計(jì)算兩個(gè)數(shù)字相加的結(jié)果。變量 multiIArguments
的類型是 IMultiArguments<Integer>听哭,它不是兩個(gè)數(shù)字相加的和慢洋,而是將兩個(gè)數(shù)字相加的那行代碼塘雳。
主體用被{}包裹的 Lambda 表達(dá)式
清單七
public class LambdaLearn {
public static void main(String[] args) {
INoArguments multiStatement = () -> {
System.out.println("this is the first code");
System.out.println("this is the second code");
};
INoArguments oneStatement = () -> {
System.out.println("only one code");
};
}
}
interface INoArguments {
void printOperation();
}
清單七中展示了,如果 Lambda 表達(dá)式的主體有多行代碼普筹,那么就需要將多行代碼用**中括號(hào) {} **包裹败明。其實(shí)當(dāng) Lambda 表達(dá)式的主體只有一行代碼的時(shí)候,大家可以根據(jù)自己的習(xí)慣決定是否使用中括號(hào)太防。
通過(guò) Lambda 表達(dá)式來(lái)看 Java8
既成事實(shí)地final變量
在我們學(xué) Java 基礎(chǔ)的時(shí)候妻顶,我們就知道匿名內(nèi)部類只能引用外部的 final 變量。但我們卻發(fā)現(xiàn)蜒车,被 Lambda 表達(dá)式引用的外部變量并沒(méi)有被 final 修飾讳嘱。如清單八中的代碼所示,被 Lambda 表達(dá)式引用的外部變量 a 和 b 并誒有被 final 修飾酿愧,這是因?yàn)?Java8 為我們省去了一些操作沥潭,這樣代碼看上去會(huì)更加干凈舒服。雖然 a 和 b 沒(méi)有被顯示地被 final 修飾嬉挡,但它們依然是事實(shí)上的 final 變量钝鸽。你們可以根據(jù)自己的喜好,選擇性地給被 Lambda 表達(dá)式引用的外部變量加上 final 修飾符庞钢。
清單八
public static void main(String[] args) {
int a = 1, b = 2;
IIntegerMath integerMath = () -> a + b;
int result = add(integerMath);
System.out.println(result);
}
類型推斷
不知大家是否有注意拔恰,本文中使用的 Lambda 表達(dá)式都沒(méi)有為參數(shù)指明類型,這是因?yàn)?Java8 引入了比 Java7 更加強(qiáng)大的目標(biāo)類型推斷基括。如清單九中的代碼所示颜懊, Lambda 表達(dá)式的參數(shù) x 并沒(méi)有被指明類型,但 javac 會(huì)根據(jù)變量 atLeast 的類型 Predicate<Integer> 推斷出目標(biāo)類型阱穗。在日常的開(kāi)發(fā)中饭冬,請(qǐng)大家根據(jù)具體情況選擇是否給 Lambda 表達(dá)式的參數(shù)顯示地指明類型。
清單九
Predicate<Integer> atLeast = x -> x > 5;
interface Predicate<Integer> {
boolean test(T t);
}
彩蛋
其實(shí)我的微信里有關(guān)注很多技術(shù)公眾號(hào)揪阶,但真正喜歡并經(jīng)常閱讀的卻寥寥無(wú)幾昌抠,其中劉欣大神的碼農(nóng)翻身就是我非常喜歡的一個(gè)公眾號(hào)。劉欣大哥是一個(gè)有 15 年工作經(jīng)驗(yàn)的前 IBM 架構(gòu)師鲁僚,他是一個(gè)熱愛(ài)編程的資深碼農(nóng)炊苫,他用心去寫(xiě)好每一篇博客,他的每篇博客都是一個(gè)故事冰沙,他用一個(gè)個(gè)精彩短小的故事解釋有點(diǎn)枯燥的技術(shù)侨艾。下面是他公眾號(hào)的二維碼,請(qǐng)關(guān)注他拓挥,你們會(huì)收獲很多唠梨。
![碼農(nóng)翻身](https://static.oschina.net/uploads/img/201708/22223452_yRz7.jpg)