2015-12-13 17 views
19

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.)

+5

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

+5

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'. –

+0

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. –

Odpowiedz

14

Istnieją specyfikacje określające minimalne gwarancje, na których może polegać osoba dzwoniąca, nie opisywać, co robi implementacja. Różnica ta ma kluczowe znaczenie, ponieważ pozwala ewoluować elastyczności wdrażania. (Specyfikacja jest deklaratywna, implementacja jest niezbędna). Zbyt szczegółowe określenie jest tak samo złe jak underspecyfikacja.

Gdy specyfikacja mówi "nie zachowuje własności X", nie oznacza to, że właściwość X może nigdy nie zostać zachowana; oznacza to, że wdrożenie nie jest zobowiązane do jej zachowania. Twoja domniemana implikacja, że ​​spotkanie z zamówieniem nigdy nie jest zachowane, jest po prostu błędnym wnioskiem. (HashSet nie obiecuje, że iteracja jego elementów zachowuje kolejność, w jakiej zostały wstawione, ale to nie znaczy, że nie może się to zdarzyć przypadkowo - po prostu nie można na to liczyć.)

Podobnie, implikacja "sugeruje dla Any jest przeznaczona do zachowania porządku dla sekwencyjnych strumieni", ponieważ zobaczyłeś implementację, która czyni to w niektórych przypadkach jest równie niepoprawna.

W obu przypadkach wydaje się, że po prostu czujesz się niekomfortowo z tym, że specyfikacja zapewnia forEach dużą swobodę. W szczególności ma swobodę nie zachowywania kolejności spotkań dla sekwencyjnych strumieni, nawet jeśli taka jest obecnie implementacja, a ponadto trudno jest sobie wyobrazić implementację, która nie jest w stanie przetworzyć kolejnych źródeł w kolejności. Ale tak właśnie mówi spec i właśnie to zamierzano powiedzieć.

To powiedziawszy, sformułowanie komentarza na temat równoległych strumieni jest potencjalnie mylące, ponieważ nadal można go źle zinterpretować. Intencją wyraźnego wskazania tego równoległego przypadku było pedagogiczne; specyfikacja jest wciąż doskonale jasna, ponieważ to zdanie zostało całkowicie usunięte. Jednak dla czytelnika, który jest nieświadomy paralelizmu, byłoby prawie niemożliwe, aby nie założyć, że forEach zachowałoby porządek spotkania, więc to zdanie zostało dodane, aby pomóc wyjaśnić motywację. Ale, jak podkreślasz, chęć potraktowania sprawy sekwencyjnej jest wciąż tak potężna, że ​​byłoby bardziej korzystne wyjaśnienie.

+2

Jestem całkowicie na pokładzie ze specyfikacjami pozwalającymi na swobodę implementacji. Chciałem tylko jednoznacznego oświadczenia, więc nie musiałem się spierać z deweloperami NetBeans o ich błędzie. (Jeśli chodzi o "nigdy", zastanawiałem się "niezależnie od tego, czy strumień jest zamówiony", czy "musi przetasować kolejność", ale oczywiście nieuporządkowany strumień nie ma żadnego porządku do zachowania). Oprócz wyjaśnienia tekstu, może dodanie "@see forEachOrdered" pokazuje programistę, że istnieje możliwość wyboru. –

+1

@JeffreyBosboom Tak, to też pomoże. Kluczową kwestią tutaj (i jest to oczywiście trudniejsze niż się wydaje, ponieważ nie udało nam się uzyskać 100% racji za pierwszym razem) pomaga ludziom pozbyć się ich wszechobecnej tendencji sekwencyjnej. Nawet pojęcie "ma zdefiniowaną kolejność spotkań" jest mylące dla wielu osób! –

+1

Myślę, że cel ten można wyjaśnić, usuwając słowa "gwarancja do" z drugiego zdania. To bardziej wyraźnie wskazywałoby, że jest to dokument implementacyjny, a nie specyfikacja specyficzna dla strumieni równoległych. – shmosel

Powiązane problemy