2 回答

TA貢獻(xiàn)2011條經(jīng)驗(yàn) 獲得超2個(gè)贊
不可以。 Streams 可能會(huì)根據(jù)需要延遲評(píng)估,并且操作順序沒有嚴(yán)格定義,尤其是在您peek()
ing 時(shí)。這允許流 API 支持非常大的流,而不會(huì)浪費(fèi)大量時(shí)間和內(nèi)存,并允許某些實(shí)現(xiàn)簡(jiǎn)化。特別是,管道的單個(gè)階段不需要在下一個(gè)階段之前被完全評(píng)估。
根據(jù)您的假設(shè),假設(shè)以下代碼將是多么浪費(fèi):
IntStream.range(1, 1000000).skip(5).limit(10).forEach(System::println);
流以 100 萬個(gè)元素開始,以 10 個(gè)元素結(jié)束。如果我們對(duì)每個(gè)階段進(jìn)行全面評(píng)估,我們的中間元素將分別為 100 萬、999995 和 10 個(gè)元素。
作為第二個(gè)示例,以下流不能一次評(píng)估一個(gè)階段(因?yàn)?code>IntStream.generate返回無限流):
IntStream.generate(/* some supplier */).limit(10).collect(Collectors.toList());
您的管道確實(shí)通過第一個(gè)元素傳遞每一個(gè)元素peek
,然后通過第二個(gè)元素只傳遞一個(gè)子集peek
。但是,管道以元素優(yōu)先而不是階段優(yōu)先順序執(zhí)行此評(píng)估:它評(píng)估管道為 1,將其放在過濾器上,然后是 2。一旦它評(píng)估管道為 3,它通過過濾器因此兩者都偷看語句執(zhí)行,然后在 4 和 5 上發(fā)生相同的情況。

TA貢獻(xiàn)1856條經(jīng)驗(yàn) 獲得超5個(gè)贊
Andrey Akhmetov 的回答是正確的,但我想補(bǔ)充一下,因?yàn)檫@里有兩個(gè)問題。一個(gè)是流管道語義的一般問題——這正是您的問題所在。第二個(gè)是關(guān)于 的含義和限制peek()
。
對(duì)于主要問題 - 與 無關(guān)peek()
,除了你如何觀察正在發(fā)生的事情的狀態(tài) - 你對(duì)流的直覺是完全不正確的。沒有理由相信:
collection.stream() .filter(x -> x.foo() > 3) .map(X::toBar) .forEach(b -> System.out.println("Bar: " + b);
所有過濾都發(fā)生在所有打印之前的所有映射之前。該流可以自由地以它喜歡的任何順序交錯(cuò)過濾、映射和打印。(總體上有一些排序保證。)這里的好處是,在某些具有無限流的情況下,這通常更高效、更可并行且更健壯。只要您遵守規(guī)則(即,不要依賴一個(gè)階段在另一個(gè)階段的副作用),您將無法區(qū)分,除非您的代碼運(yùn)行得更快。
的語言搖擺不定的原因peek()
是對(duì)于管道,例如:
int size = collection.stream() .map(...) .peek(...) .count()
我們可以在不進(jìn)行任何映射的情況下評(píng)估答案(因?yàn)橐阎?map() 是一種保持大小的操作。)始終在peek()
點(diǎn)處提供元素的要求會(huì)破壞許多有用的優(yōu)化。因此,如果可以證明它不會(huì)影響答案,則實(shí)現(xiàn)可以自由地省略整個(gè)管道中間。(它可能會(huì)產(chǎn)生更少的副作用,但如果你非常關(guān)心副作用,也許你不應(yīng)該使用流。)
添加回答
舉報(bào)