Javadoc dla Stream.forEach
mówi (Kopalnia nacisk):Czy Stream.forEach przestrzega kolejności spotkań w sekwencyjnych strumieniach?
Zachowanie tej operacji jest wyraźnie niedeterministyczny. W przypadku potoków o równoległych potokach operacja ta nie gwarantuje przestrzegania kolejności spotkań strumienia, ponieważ spowodowałoby to korzyść równoległości. Dla dowolnego elementu akcja może być wykonana w dowolnym momencie i w dowolnym wątku wybranym przez bibliotekę. Jeśli akcja uzyskuje dostęp do współdzielonego stanu, odpowiada za zapewnienie wymaganej synchronizacji.
Ten sam tekst jest obecny w Java 9 Early Access Javadoc.
Pierwsze zdanie ("wyraźnie niedeterministyczne") sugeruje (ale nie mówi wprost), że kolejność spotkań nie jest zachowywana tą metodą. Ale następne zdanie, które wyraźnie mówi, że porządek nie jest zachowany, jest uwarunkowane "Dla równoległych potoków potokowych", a warunek ten byłby niepotrzebny, gdyby zdanie było stosowane niezależnie od równoległości. W związku z tym nie jestem pewien, czy dla Każdą opcję zachowuje kolejność spotkań dla sekwencyjnych strumieni.
This answer wskazuje miejsce, w którym implementacja biblioteki strumieniowej calls .sequential().forEach(downstream)
. Sugeruje to, że dlaEach ma na celu zachowanie porządku dla sekwencyjnych strumieni, ale może też być po prostu błędem w bibliotece.
Mam pominął tę dwuznaczność w mój własny kod za pomocą forEachOrdered
być na bezpiecznej stronie, ale dziś odkryłem, że NetBeans IDE „użytkowania funkcjonalny operacji” podpowiedź edytor konwertować
for (Foo foo : collection)
foo.bar();
do
collection.stream().forEach((foo) -> {
foo.bar();
});
co wprowadza błąd, jeśli dlaEniza nie zachowuje kolejności spotkań. Zanim zgłoszę a bug against NetBeans, chcę wiedzieć, co biblioteka faktycznie gwarantuje, kopii zapasowej przez źródło.
Poszukuję wzoru odpowiedzi z autorytatywnych źródeł. To może być wyraźny komentarz w implementacji biblioteki, dyskusja na temat list dyskusyjnych na temat programowania Java (Google nic nie znalazło, ale może nie znam magicznych słów) lub oświadczenie od projektantów bibliotek (z których znać dwa, Brian Goetz i Stuart Marks, są aktywne w przepełnieniu stosu). (Nie odpowiadaj słowem "po prostu używaj zamiast opcjiEachOrdered" - już to robię, ale chcę się dowiedzieć, czy kod, który nie jest nieprawidłowy.)
Dokumentacja jest dość jasna. 'forEach' ignoruje" uporządkowaną "właściwość wszystkich strumieni, równoległych/sekwencyjnych, uporządkowanych/nieuporządkowanych. Nie ma wyjątków. Nawet jeśli w bieżącej implementacji strumieni nie ma kodu, który spowodowałby brak kolejności na sekwencyjne strumienie, ta opcja pozostanie otwarta na przyszłość. – zapl
Pytanie jest w gruncie rzeczy głębsze: czy nieuporządkowana charakterystyka strumienia ma znaczenie dla sekwencyjnego strumienia (lub może mieć znaczenie w przyszłości). Obecnie sekwencyjny strumień nieuporządkowany jest zawsze przetwarzany tak, jak zamówiono, ale wiele optymalizacji może być wykonywanych, gdy źródło lub terminal op jest nieuporządkowany. Na przykład '.distinct()' używa 'LinkedHashSet' do zachowania porządku. Może użyć po prostu 'HashSet' z mniejszym narzutem, jeśli op jest opcją' forEach' lub 'findAny'. –
Ponadto, dość powszechne jest założenie, że przetwarzanie w kolejności jest konieczne, nawet w przypadkach, w których nie jest. Jest to efekt uboczny wszechobecnej sekwencyjności, z którą wszyscy dorośli; w porządku była tak łatwa i tak tania od tak dawna, że łatwo nie kwestionować założenia, że jest ona potrzebna, nawet gdy jej nie ma. –