(補(bǔ))Java Lambda表達(dá)(二)

例5灭抑、如何在lambda表達(dá)式中加入Predicate

上個(gè)例子說(shuō)到泉孩,java.util.function.Predicate 允許將兩個(gè)或更多的 Predicate 合成一個(gè)。它提供類似于邏輯操作符AND和OR的方法,名字叫做and()、or()和xor()善已,用于將傳入 filter() 方法的條件合并起來(lái)。例如离例,要得到所有以J開(kāi)始换团,長(zhǎng)度為四個(gè)字母的語(yǔ)言,可以定義兩個(gè)獨(dú)立的 Predicate 示例分別表示每一個(gè)條件宫蛆,然后用 Predicate.and() 方法將它們合并起來(lái)艘包,如下所示:

// 甚至可以用and()、or()和xor()邏輯函數(shù)來(lái)合并Predicate耀盗,
// 例如要找到所有以J開(kāi)始想虎,長(zhǎng)度為四個(gè)字母的名字,你可以合并兩個(gè)Predicate并傳入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
    .filter(startsWithJ.and(fourLetterLong))
    .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));

類似地叛拷,也可以使用 or() 和 xor() 方法磷醋。本例著重介紹了如下要點(diǎn):可按需要將 Predicate 作為單獨(dú)條件然后將其合并起來(lái)使用。簡(jiǎn)而言之胡诗,你可以以傳統(tǒng)Java命令方式使用 Predicate 接口,也可以充分利用lambda表達(dá)式達(dá)到事半功倍的效果淌友。

例6煌恢、Java 8中使用lambda表達(dá)式的Map和Reduce示例

本例介紹最廣為人知的函數(shù)式編程概念map。它允許你將對(duì)象進(jìn)行轉(zhuǎn)換震庭。例如在本例中瑰抵,我們將 costBeforeTax 列表的每個(gè)元素轉(zhuǎn)換成為稅后的值。我們將 x -> x*x lambda表達(dá)式傳到 map() 方法器联,后者將其應(yīng)用到流中的每一個(gè)元素二汛。然后用 forEach() 將列表元素打印出來(lái)婿崭。使用流API的收集器類,可以得到所有含稅的開(kāi)銷肴颊。有 toList() 這樣的方法將 map 或任何其他操作的結(jié)果合并起來(lái)氓栈。由于收集器在流上做終端操作,因此之后便不能重用流了婿着。你甚至可以用流API的 reduce() 方法將所有數(shù)字合成一個(gè)授瘦,下一個(gè)例子將會(huì)講到。

// 不使用lambda表達(dá)式為每個(gè)訂單加上12%的稅
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    System.out.println(price);
}
 
// 使用lambda表達(dá)式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);

輸出:

112.0
224.0
336.0
448.0
560.0
112.0
224.0
336.0
448.0
560.0

例6.2竟宋、Java 8中使用lambda表達(dá)式的Map和Reduce示例

在上個(gè)例子中提完,可以看到map將集合類(例如列表)元素進(jìn)行轉(zhuǎn)換的。還有一個(gè) reduce() 函數(shù)可以將所有值合并成一個(gè)丘侠。Map和Reduce操作是函數(shù)式編程的核心操作徒欣,因?yàn)槠涔δ埽瑀educe 又被稱為折疊操作蜗字。另外打肝,reduce 并不是一個(gè)新的操作,你有可能已經(jīng)在使用它秽澳。SQL中類似 sum()闯睹、avg() 或者 count() 的聚集函數(shù),實(shí)際上就是 reduce 操作担神,因?yàn)樗鼈兘邮斩鄠€(gè)值并返回一個(gè)值楼吃。流API定義的 reduceh() 函數(shù)可以接受lambda表達(dá)式,并對(duì)所有值進(jìn)行合并妄讯。IntStream這樣的類有類似 average()孩锡、count()、sum() 的內(nèi)建方法來(lái)做 reduce 操作亥贸,也有mapToLong()躬窜、mapToDouble() 方法來(lái)做轉(zhuǎn)換。這并不會(huì)限制你炕置,你可以用內(nèi)建方法荣挨,也可以自己定義。在這個(gè)Java 8的Map Reduce示例里朴摊,我們首先對(duì)所有價(jià)格應(yīng)用 12% 的VAT默垄,然后用 reduce() 方法計(jì)算總和。

// 為每個(gè)訂單加上12%的稅
// 老方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    total = total + price;
}
System.out.println("Total : " + total);
 
// 新方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
System.out.println("Total : " + bill);

輸出:

Total : 1680.0
Total : 1680.0

例7甚纲、通過(guò)過(guò)濾創(chuàng)建一個(gè)String列表

過(guò)濾是Java開(kāi)發(fā)者在大規(guī)模集合上的一個(gè)常用操作口锭,而現(xiàn)在使用lambda表達(dá)式和流API過(guò)濾大規(guī)模數(shù)據(jù)集合是驚人的簡(jiǎn)單。流提供了一個(gè) filter() 方法介杆,接受一個(gè) Predicate 對(duì)象鹃操,即可以傳入一個(gè)lambda表達(dá)式作為過(guò)濾邏輯韭寸。下面的例子是用lambda表達(dá)式過(guò)濾Java集合,將幫助理解荆隘。

// 創(chuàng)建一個(gè)字符串列表恩伺,每個(gè)字符串長(zhǎng)度大于2
List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

輸出:

Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]

另外,關(guān)于 filter() 方法有個(gè)常見(jiàn)誤解臭胜。在現(xiàn)實(shí)生活中莫其,做過(guò)濾的時(shí)候,通常會(huì)丟棄部分耸三,但使用filter()方法則是獲得一個(gè)新的列表乱陡,且其每個(gè)元素符合過(guò)濾原則。

例8仪壮、對(duì)列表的每個(gè)元素應(yīng)用函數(shù)

我們通常需要對(duì)列表的每個(gè)元素使用某個(gè)函數(shù)憨颠,例如逐一乘以某個(gè)數(shù)、除以某個(gè)數(shù)或者做其它操作积锅。這些操作都很適合用 map() 方法爽彤,可以將轉(zhuǎn)換邏輯以lambda表達(dá)式的形式放在 map() 方法里,就可以對(duì)集合的各個(gè)元素進(jìn)行轉(zhuǎn)換了缚陷,如下所示适篙。

// 將字符串換成大寫并用逗號(hào)鏈接起來(lái)
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

輸出:

USA, JAPAN, FRANCE, GERMANY, ITALY, U.K., CANADA

例9、復(fù)制不同的值箫爷,創(chuàng)建一個(gè)子列表

本例展示了如何利用流的 distinct() 方法來(lái)對(duì)集合進(jìn)行去重嚷节。

// 用所有不同的數(shù)字創(chuàng)建一個(gè)正方形列表
List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
System.out.printf("Original List : %s,  Square Without duplicates : %s %n", numbers, distinct);

輸出:

Original List : [9, 10, 3, 4, 7, 3, 4],  Square Without duplicates : [81, 100, 9, 16, 49]

例10、計(jì)算集合元素的最大值虎锚、最小值硫痰、總和以及平均值

IntStream、LongStream 和 DoubleStream 等流的類中窜护,有個(gè)非常有用的方法叫做 summaryStatistics() 效斑。可以返回 IntSummaryStatistics柱徙、LongSummaryStatistics 或者 DoubleSummaryStatistic s缓屠,描述流中元素的各種摘要數(shù)據(jù)。在本例中护侮,我們用這個(gè)方法來(lái)計(jì)算列表的最大值和最小值敌完。它也有 getSum() 和 getAverage() 方法來(lái)獲得列表的所有元素的總和及平均值。

//獲取數(shù)字的個(gè)數(shù)概行、最小值、最大值弧岳、總和以及平均值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());

輸出:

Highest prime number in List : 29
Lowest prime number in List : 2
Sum of all prime numbers : 129
Average of all prime numbers : 12.9

Lambda表達(dá)式 vs 匿名類

既然lambda表達(dá)式即將正式取代Java代碼中的匿名內(nèi)部類凳忙,那么有必要對(duì)二者做一個(gè)比較分析业踏。一個(gè)關(guān)鍵的不同點(diǎn)就是關(guān)鍵字 this。匿名類的 this 關(guān)鍵字指向匿名類涧卵,而lambda表達(dá)式的 this 關(guān)鍵字指向包圍lambda表達(dá)式的類勤家。另一個(gè)不同點(diǎn)是二者的編譯方式。Java編譯器將lambda表達(dá)式編譯成類的私有方法柳恐。使用了Java 7的 invokedynamic 字節(jié)碼指令來(lái)動(dòng)態(tài)綁定這個(gè)方法伐脖。

歡迎加入學(xué)習(xí)交流群569772982,大家一起學(xué)習(xí)交流乐设。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讼庇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子近尚,更是在濱河造成了極大的恐慌蠕啄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戈锻,死亡現(xiàn)場(chǎng)離奇詭異歼跟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)格遭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門哈街,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拒迅,你說(shuō)我怎么就攤上這事骚秦。” “怎么了坪它?”我有些...
    開(kāi)封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵骤竹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我往毡,道長(zhǎng)蒙揣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任开瞭,我火速辦了婚禮懒震,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嗤详。我一直安慰自己个扰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布葱色。 她就那樣靜靜地躺著递宅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上办龄,一...
    開(kāi)封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天烘绽,我揣著相機(jī)與錄音,去河邊找鬼俐填。 笑死安接,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的英融。 我是一名探鬼主播盏檐,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼驶悟!你這毒婦竟也來(lái)了胡野?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撩银,失蹤者是張志新(化名)和其女友劉穎给涕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體额获,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡够庙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抄邀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耘眨。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖境肾,靈堂內(nèi)的尸體忽然破棺而出剔难,到底是詐尸還是另有隱情,我是刑警寧澤奥喻,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布偶宫,位于F島的核電站,受9級(jí)特大地震影響环鲤,放射性物質(zhì)發(fā)生泄漏纯趋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一冷离、第九天 我趴在偏房一處隱蔽的房頂上張望吵冒。 院中可真熱鬧,春花似錦西剥、人聲如沸痹栖。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揪阿。三九已至疗我,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間南捂,已是汗流浹背碍粥。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黑毅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓钦讳,卻偏偏與公主長(zhǎng)得像矿瘦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子愿卒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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