何時(shí)使用Java Stream,何時(shí)使用Java集合框架
本文轉(zhuǎn)載自微信公眾號(hào)「碼農(nóng)小胖哥」,作者碼農(nóng)小胖哥 。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼農(nóng)小胖哥公眾號(hào)。
Java 8 的Stream API 提供了不少可替代Java 集合框架的操作。但是不少同學(xué)在學(xué)習(xí)和使用Stream時(shí)依然感到很困惑,不知道何時(shí)使用Stream,甚至想不起來(lái)使用Stream,甚至在Stream和集合框架的選擇上也成了問(wèn)題。今天胖哥將嘗試幫你解決這些疑問(wèn)。
本文已經(jīng)假設(shè)你入門(mén)過(guò)了Stream,你也可以通過(guò)這一篇來(lái)入門(mén)學(xué)習(xí)。
Stream的特點(diǎn)
如果你要用好Stream,你必須搞清楚它的特點(diǎn)。
Stream 并非數(shù)據(jù)結(jié)構(gòu)
雖然我們把Stream和以Collection為代表的集合框架類型放在一起對(duì)比,但它只是將數(shù)據(jù)源(Source)中的數(shù)據(jù)元素提取到數(shù)據(jù)操作管道,并按照定義好的規(guī)則(操作符)進(jìn)行“流動(dòng)”。另外Stream也絕不修改自己所封裝的底層數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)。
Stream有點(diǎn)類似于水管網(wǎng)絡(luò)。
無(wú)固定大小
水管網(wǎng)絡(luò)中流動(dòng)的水是沒(méi)有固定大小的,甚至可以是無(wú)限的。Stream也是如此。
惰性化
Stream只有定義終止操作,比如collect(Collector)、forEach(Consumer),它才會(huì)開(kāi)始執(zhí)行。以下從流中篩選以h開(kāi)頭的字符串并不會(huì)執(zhí)行。
- Stream.of("hello","wolrd").filter(str-> str.startsWith("h"))
不變性
一個(gè)既定的Stream是不變的,所有的中間操作都會(huì)衍生一個(gè)新的Stream,即使中間操作不改變Stream中的任何元素。
一次性
一個(gè)Stream流只有一次終止操作。一旦完成了終止操作,這個(gè)流就關(guān)閉了。無(wú)法再次進(jìn)行使用,簡(jiǎn)直就是一次性用品。
- Stream<String> stringStream = Stream.of("1", "2");
- // forEach 終止操作打印 1 2 流終止
- stringStream.forEach(System.out::println);
- // 重復(fù)使用將拋出IllegalStateException異常 stream has already been operated upon or closed
- stringStream.filter(s -> s.equals("2")).forEach(System.out::println);
并行操作
Stream支持并行化(parallel)操作,不需要編寫(xiě)額外的多線程代碼,所有的操作會(huì)自動(dòng)并行進(jìn)行。不過(guò)大多數(shù)情況下我們都是串行執(zhí)行。
我們?cè)撊绾芜x擇
對(duì)于Stream和Collection我們?cè)撊绾芜x擇呢?首先Collection的絕大部分場(chǎng)景Stream都可以完成,甚至更好。
看API操作
它們都提供了很多方法,如果你需要獲取元素的個(gè)數(shù),集合更加方便一些,如果你要過(guò)濾一些元素,很明顯,Stream的API更加方便,甚至它提供了各種可組合的操作。
看初始化成本
對(duì)于集合,一旦定義使用需要一次性的加載入內(nèi)存,如果你打算在內(nèi)存中重用這些數(shù)據(jù),使用集合就非常合適;而Stream的惰性特點(diǎn),在終端操作之前不會(huì)有任何的中間操作,這意味著不會(huì)上來(lái)就初始化數(shù)據(jù)到內(nèi)存,可以降低初始化成本,甚至你可以調(diào)整其執(zhí)行消費(fèi)元素的速率。
看結(jié)果集大小
如果最終的結(jié)果是可控的、有限的,它們兩者都能夠勝任;如果結(jié)果集非常龐大或者近似無(wú)限的,Stream將是不二之選。
是否改變?cè)紨?shù)據(jù)
Stream不會(huì)改變?cè)嫉臄?shù)據(jù),而Collection可以實(shí)現(xiàn)這一點(diǎn)。
是要數(shù)據(jù)容器還是數(shù)據(jù)管道。
是否需要重用對(duì)象實(shí)例
當(dāng)結(jié)果以Collection的形式返回時(shí),我們可以重復(fù)使用。而一個(gè)Stream被使用后,就認(rèn)為它已消耗掉,并在重用時(shí)拋出IllegalStateException,如上面所示。
是否需要固定的格式
Stream流的表現(xiàn)格式通常沒(méi)有Java集合框架豐富,Java集合框架提供了如Set、List、Map等格式。如果你需要終端返回展現(xiàn),顯然集合框架更加合適。
在Spring MVC中,Stream的展現(xiàn)為數(shù)組。
總結(jié)
以上是在使用這兩個(gè)概念需要考慮的幾個(gè)點(diǎn),其實(shí)大多數(shù)情況下,我們只需要看誰(shuí)的API更加友好,因?yàn)樗鼈冎g可以相互轉(zhuǎn)換。顯而易見(jiàn),Stream更加符合未來(lái)的趨勢(shì)。