2016-09-26 42 views
8

鑑於我有一個流Stream<T> stream = list.stream().filter(some predicate)其中列表是非常大的,它是更有效的檢查流是否是通過做非空:stream.count() > 0或做:stream.findFirst().isPresent()Java 8 findFirst()。isPresent()比count()> 0更有效嗎?

+0

它取決於它是哪個'List'實現,但它甚至沒有可比性,因爲它將您移動到流中。 – EJP

+6

對於無限流,count()不會終止;即使對於有限的流,它也必須在返回之前遍歷整個流。而'findFirst()'或'findAny()'或'anyMatch(e - > true)'是短路的,它們在找到元素時會停止。 –

+3

這裏真正的教訓是,正確的問題不在於效率,而在於正確性。使用findXxx或xxxMatch最好不是因爲它們更有效率,而是因爲它們更接近表達你想要了解的屬性。他們碰巧效率更高只是對圖書館提出了更好的查詢的一個令人愉快的副作用。 –

回答

5

如果你想知道的是,是否有匹配,你應該使用
list.stream().anyMatch(some predicate),不僅因爲它是更有效,而且,因爲它是表達你的意圖正確的成語。

正如有人說,anyMatch是短路,這意味着它會停在第一場比賽,而count會,顧名思義,返回前數所有匹配。根據流的內容,這可能會產生巨大的性能差異。但要注意,就可以使count同樣有效,通過使用 list.stream().filter(some predicate).limit(1).count() > 0

然後,它也將停止在第一次出現後,但是,正如所說,anyMatch仍然表達,你有興趣是否存在的首選方式是任何匹配。事情的變化,當任務是找出是否有至少n匹配。然後,.limit(n).count() > n-1(或>= n)成爲自然的成語。

注意findFirst()與其他解決方案不同,因爲它的答案取決於排序。所以如果你只想知道是否有匹配,你應該使用findAny()。不過,有一個理論上的差異,由於在返回的匹配值的要求相比,只是告訴是否有匹配,像anyMatch確實,雖然目前是不同的只是一個Optional實例的製作,因此,可以忽略不計。

但既然你對編程的API來編碼你的意圖,則不應使用find…當你只是想知道是否有匹配。 anyMatch明確表達了您的意圖,並且在未來的實施或更復雜的情況下可能會有更高的收益。

11

我建議使用list.stream().anyMatch(some predicate),這是正是這種情況下的終端的操作。它不僅比stream.count()更高效,但它不會掛在無限的流上。

+1

好點,掛在無限的溪流上! –

+0

@Holger這聽起來像你不同意我說的話。 – shmosel

+0

也許我昨天在你的回答中誤讀了一些東西,我猜,我忽略了「唯一」......如果你想知道的話,我沒有降低評分。 – Holger

2

findAny(如果你不需要排序而最好findFirst)和anyMatchshort-circuiting operations,這意味着它們可以在不消耗整個流,如果條件允許提前返回。這是在他們的方法javadocs中提到並鏈接的。 count()is not

如果流的最後階段仍然採用與SIZED特性的spliterator然後count()可以是一樣快,其他兩個選項。但是這是一個比短路更弱的特性,因爲中間流操作(如filter())很可能會丟棄SIZED方面。

所有這些信息都可以從包裝文檔中找到,因此強烈推薦閱讀。

+1

由於該問題的代碼合併了「過濾器」操作,因此無法測試每個元素以獲取匹配元素的數量。除了熱點優化器可能檢測到(在順序上下文中)計算計數不是必需的,因爲如何使用結果數字。無論哪種情況,「count」都是最差的賭注。 – Holger

+0

@霍爾我沒有要求過。我只想提一提,在有限的情況下,「count」可能會一樣快。一個可以想象的優化就像是一個'.filter(Predictate.TRUE)'(如果存在的話)保存源分割器。 – the8472

+2

我只是想提一下,可預見的大小可能出現的情況是衆所周知的(這就是爲什麼我把它從我的答案中排除,因爲它在這裏不適用),以及不存在總是「真實」謂詞,這可能不會那麼戲劇性,但更糟糕的是,在Oracle的JRE/OpenJDK中,直到Java 9 ... – Holger