2016-12-27 17 views
7

Innymi słowy, czy następująca linia jest gwarantująca wydrukowanie linii num?Czy Stream.count() gwarantuje obecność w każdym elemencie?

int num = list.stream().peek(System.out::println).count(); 

To pytanie zostało wywołane przez dyskusji w komentarzach https://stackoverflow.com/a/41346586/2513200

I mgliście pamiętam dyskusję, że optymalizacje, że trzeba unikać iteracji może być legalne, ale nie znaleźliśmy nic rozstrzygającego podczas szybkiego wyszukiwania.

JavaDocs for Stream.count zawierać to oświadczenie:

Jest to szczególny przypadek redukcji i odpowiada:
return mapToLong(e -> 1L).sum();

ale nie jestem pewien, czy to daje żadnych gwarancji, jeśli strumień może w jakiś sposób określić wynik w sposób zwarcia.

+3

Zostanie zmodyfikowany w Javie 9 (patrz uwaga do API): http://download.java.net/java/jdk9/docs/api/java/util/stream/Stream.html#count-- –

+0

Parametr _result_ jest wymagany, nie można niczego wykonać. – Cubic

+4

Tuż po tej części dokumentacji znajdziesz: "Implementacja może nie wykonywać potoku potoku [...], jeśli jest w stanie obliczać liczbę bezpośrednio ze źródła strumienia. W takich przypadkach żadne elementy źródłowe nie będą przechodzić i nie będą oceniane żadne operacje pośrednie. " –

Odpowiedz

13

Nie, nie jest. Nie zrobi tego w Javie 9 ze względu na zoptymalizowaną implementację count() (jeśli rozmiar strumienia jest znany z góry, pominie iterację).

Aby uzyskać więcej informacji, zobacz JDK-8067969. Dokumentacja w JDK-9 został odpowiednio zaktualizowany:

Implementacja może wybrać, aby nie wykonać strumień rurociągowy (albo sekwencyjnie lub równolegle), jeżeli jest on zdolny do obliczania liczby bezpośrednio od źródła strumienia. W takich przypadkach nie będą wykonywane żadne elementy źródłowe i nie zostaną ocenione żadne operacje pośrednie. Może to mieć wpływ na parametry behawioralne z efektami ubocznymi, które są zdecydowanie odradzane, z wyjątkiem nieszkodliwych przypadków, takich jak debugowanie.

+2

Najprawdopodobniej iteracja zostanie pominięta, gdy rozdzielacz podziału jest SIZED. –

+1

@ Jean-FrançoisSavard, dokładniej, jeśli ostatni strumień ma SIZED StreamOpFlag. StreamOpFlags są podobne do charakterystyki spliteratora, ale nieco inne. Jeśli masz operacje pośrednie, nie masz dla nich dzielnika, ale masz StreamOpFlags. Z pośrednim 'map()' lub 'peek()' masz się dobrze, ale pośrednie 'filter()' lub 'distinct()' wyczyści SIZED. –