java stream api中的reduce方法使用

java stream api中的reduce方法使用

java stream api是對(duì)函數(shù)式編程的支持姆另,雖然stream api和c# linq比起來就是拖拉機(jī)和法拉利的區(qū)別,不過勉強(qiáng)能用坟乾,總比沒有強(qiáng)迹辐。

stream api的reduce方法用于對(duì)stream中元素進(jìn)行聚合求值,最常見的用法就是將stream中一連串的值合成為單個(gè)值甚侣,比如為一個(gè)包含一系列數(shù)值的數(shù)組求和明吩。

reduce方法有三個(gè)重載的方法,方法簽名如下

Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);

第一個(gè)簽名方法接受一個(gè)BinaryOperator類型的lambada表達(dá)式殷费, 常規(guī)應(yīng)用方法如下

List<Integer> numList = Arrays.asList(1,2,3,4,5);
int result = numList.stream().reduce((a,b) -> a + b ).get();
System.out.println(result);

代碼實(shí)現(xiàn)了對(duì)numList中的元素累加印荔。lambada表達(dá)式的a參數(shù)是表達(dá)式的執(zhí)行結(jié)果的緩存,也就是表達(dá)式這一次的執(zhí)行結(jié)果會(huì)被作為下一次執(zhí)行的參數(shù)详羡,而第二個(gè)參數(shù)b則是依次為stream中每個(gè)元素仍律。如果表達(dá)式是第一次被執(zhí)行,a則是stream中的第一個(gè)元素殷绍。

int result = numList.stream().reduce((a,b) -> {
  System.out.println("a=" + a + ",b=" + b);
  return a + b;
} ).get();

在表達(dá)式中假如打印參數(shù)的代碼染苛,打印出來的內(nèi)容如下

a=1,b=2
a=3,b=3
a=6,b=4
a=10,b=5

表達(dá)式被調(diào)用了4次鹊漠, 第一次a和b分別為stream的第一和第二個(gè)元素主到,因?yàn)榈谝淮螞]有中間結(jié)果可以傳遞, 所以 reduce方法實(shí)現(xiàn)為直接將第一個(gè)元素作為中間結(jié)果傳遞躯概。

第二個(gè)簽名的實(shí)現(xiàn)

T reduce(T identity, BinaryOperator<T> accumulator);

與第一個(gè)簽名的實(shí)現(xiàn)的唯一區(qū)別是它首次執(zhí)行時(shí)表達(dá)式第一次參數(shù)并不是stream的第一個(gè)元素登钥,而是通過簽名的第一個(gè)參數(shù)identity來指定。我們來通過這個(gè)簽名對(duì)之前的求和代碼進(jìn)行改進(jìn)

List<Integer> numList = Arrays.asList(1,2,3,4,5);
int result = numList.stream().reduce(0,(a,b) ->  a + b );
System.out.println(result);

其實(shí)這兩種實(shí)現(xiàn)幾乎差別娶靡,第一種比第一種僅僅多了一個(gè)字定義初始值罷了牧牢。 此外,因?yàn)榇嬖趕tream為空的情況,所以第一種實(shí)現(xiàn)并不直接方法計(jì)算的結(jié)果塔鳍,而是將計(jì)算結(jié)果用Optional來包裝伯铣,我們可以通過它的get方法獲得一個(gè)Integer類型的結(jié)果,而Integer允許null轮纫。第二種實(shí)現(xiàn)因?yàn)樵试S指定初始值腔寡,因此即使stream為空,也不會(huì)出現(xiàn)返回結(jié)果為null的情況掌唾,當(dāng)stream為空放前,reduce為直接把初始值返回。

第三種簽名的用法相較前兩種稍顯復(fù)雜糯彬,猶豫前兩種實(shí)現(xiàn)有一個(gè)缺陷凭语,它們的計(jì)算結(jié)果必須和stream中的元素類型相同,如上面的代碼示例撩扒,stream中的類型為int似扔,那么計(jì)算結(jié)果也必須為int,這導(dǎo)致了靈活性的不足搓谆,甚至無法完成某些任務(wù)虫几, 比入我們咬對(duì)一個(gè)一系列int值求和,但是求和的結(jié)果用一個(gè)int類型已經(jīng)放不下挽拔,必須升級(jí)為long類型辆脸,此實(shí)第三簽名就能發(fā)揮價(jià)值了,它不將執(zhí)行結(jié)果與stream中元素的類型綁死螃诅。

List<Integer> numList = Arrays.asList(Integer.MAX_VALUE,Integer.MAX_VALUE);
long result = numList.stream().reduce(0L,(a,b) ->  a + b, (a,b)-> 0L );
System.out.println(result);

如上代碼所示啡氢,它能見int類型的列表合并成long類型的結(jié)果。
當(dāng)然這只是其中一種應(yīng)用罷了术裸,猶豫拜托了類型的限制我們還可以通過他來靈活的完成許多任務(wù)倘是,比入將一個(gè)int類型的ArrayList轉(zhuǎn)換成一個(gè)String類型的ArrayList

List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6);
ArrayList<String> result = numList.stream().reduce(new ArrayList<String>(), (a, b) -> {
    a.add("element-" + Integer.toString(b));
    return a;
}, (a, b) -> null);
System.out.println(result);

執(zhí)行結(jié)果為

[element-1, element-2, element-3, element-4, element-5, element-6]

這個(gè)示例顯得有點(diǎn)雞肋,一點(diǎn)不實(shí)用袭艺,不過在這里我們的主要目的是說明代碼能達(dá)到什么樣的效果搀崭,因此代碼示例也不必取自實(shí)際的應(yīng)用場(chǎng)景。

從上面兩個(gè)示例可以看出第三個(gè)reduce比前面兩個(gè)強(qiáng)大的多猾编,它的功能已經(jīng)完全覆蓋前面兩個(gè)的實(shí)現(xiàn)瘤睹,如果我們不考慮代碼的簡(jiǎn)潔性,甚至可以拋棄前面兩個(gè)答倡。

另外轰传,還需要注意的是這個(gè)reduce的簽名還包含第三個(gè)參數(shù),一個(gè)BinaryOperator<U>類型的表達(dá)式瘪撇。在常規(guī)情況下我們可以忽略這個(gè)參數(shù)获茬,敷衍了事的隨便指定一個(gè)表達(dá)式即可港庄,目的是為了通過編譯器的檢查炊苫,因?yàn)樵诔R?guī)的stream中它并不會(huì)被執(zhí)行到忿晕,然而臂拓, 雖然此表達(dá)式形同虛設(shè)氧敢,可是我們也不是把它設(shè)置為null茬故,否者還是會(huì)報(bào)錯(cuò)第步。 在并行stream中煞檩,此表達(dá)式則會(huì)被執(zhí)行到定鸟,在這里我們不進(jìn)行講解稿存,因?yàn)槲易约阂矝]用過笨篷。

numList.parallelStream()

可獲得并行stream

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓣履,隨后出現(xiàn)的幾起案子率翅,更是在濱河造成了極大的恐慌,老刑警劉巖袖迎,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冕臭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡燕锥,警方通過查閱死者的電腦和手機(jī)辜贵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來归形,“玉大人托慨,你說我怎么就攤上這事∠玖瘢” “怎么了厚棵?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蔼紧。 經(jīng)常有香客問我婆硬,道長,這世上最難降的妖魔是什么奸例? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任彬犯,我火速辦了婚禮,結(jié)果婚禮上查吊,老公的妹妹穿的比我還像新娘谐区。我一直安慰自己,他們只是感情好菩貌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布卢佣。 她就那樣靜靜地躺著,像睡著了一般箭阶。 火紅的嫁衣襯著肌膚如雪虚茶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天仇参,我揣著相機(jī)與錄音嘹叫,去河邊找鬼诈乒。 笑死罩扇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怕磨。 我是一名探鬼主播喂饥,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼肠鲫!你這毒婦竟也來了员帮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤导饲,失蹤者是張志新(化名)和其女友劉穎捞高,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渣锦,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硝岗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袋毙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片型檀。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖听盖,靈堂內(nèi)的尸體忽然破棺而出贱除,到底是詐尸還是另有隱情,我是刑警寧澤媳溺,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布月幌,位于F島的核電站,受9級(jí)特大地震影響悬蔽,放射性物質(zhì)發(fā)生泄漏扯躺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一蝎困、第九天 我趴在偏房一處隱蔽的房頂上張望录语。 院中可真熱鬧,春花似錦禾乘、人聲如沸澎埠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒲稳。三九已至氮趋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間江耀,已是汗流浹背剩胁。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祥国,地道東北人昵观。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像舌稀,于是被迫代替她去往敵國和親啊犬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348