2015-09-26 20 views
35

Rozumiem, że te metody różnią się kolejnością wykonania, ale w całym moim teście nie mogę wykonać innego wykonania zlecenia.forEach kontra forEachOrdered w Javie 8 Stream

przykład:

System.out.println("forEach Demo"); 
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s)); 
System.out.println("forEachOrdered Demo"); 
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s)); 

wyjściowa:

forEach Demo 
Output:AAA 
Output:BBB 
Output:CCC 
forEachOrdered Demo 
Output:AAA 
Output:BBB 
Output:CCC 

Proszę podać przykłady metody 2, gdy będzie innych rezultatów.

+0

Spróbuj z równoległymi strumieniami. – Pshemo

+0

@Pshemo jest tylko możliwą opcją? – gstackoverflow

+3

Nieokreślona kolejność nie oznacza "gwarantowana inna kolejność".Oznacza to tylko * nieokreśloną *, co zawsze oznacza możliwość dopasowania kolejności spotkań. Nie ma wbudowanej funkcji shuffle. – Holger

Odpowiedz

42
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s)); 
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s)); 

Druga linia będzie zawsze wysyłany

Output:AAA 
Output:BBB 
Output:CCC 

natomiast pierwsza nie jest gwarantowana, ponieważ kolejność nie jest utrzymywane. forEachOrdered przetwarza elementy strumienia w kolejności określonej przez źródło, niezależnie od tego, czy strumień jest sekwencyjny, czy równoległy.

Cytując forEach Javadoc:

zachowanie tej operacji jest wyraźnie niedeterministyczny. W przypadku rurociągów o równoległym przepływie operacja ta nie gwarantuje poszanowania porządku spotkania strumienia, ponieważ w ten sposób zostałaby poświęcona korzyść równoległości.

Gdy forEachOrdered JavaDoc stanów (kopalnia nacisk)

wykonuje czynność, dla każdego elementu strumienia, w celu zetknięcie strumienia jeżeli strumień posiada określoną kolejność spotkań.

+6

Tak, masz rację. Czy jest to możliwe tylko dla parallelStreams? – gstackoverflow

+6

Nawet gdyby teraz dotyczyło to tylko strumieni równoległych - i nie twierdzę, że tak - w przyszłości może się jeszcze zepsuć, jeśli niektóre etapy pośrednie zostaną zoptymalizowane, by wykorzystać nieuporządkowane strumienie, np. sort może użyć niestabilnego algorytmu, jeśli strumień jest nieuporządkowany. – the8472

+1

Więc nie ma sensu używać 'forEachOrdered' z' parallel'? –

20

Chociaż forEach krótsza i wygląda ładniej, sugeruję użycie forEachOrdered w każdym miejscu, w którym sprawy zamów jawnie określić to. W przypadku strumieni sekwencyjnych wartość forEach wydaje się być zgodna z zamówieniem, a nawet wewnętrznym kodem strumienia API usesforEach (dla strumienia, który jest znany jako sekwencyjny), w którym semantycznie konieczne jest użycie forEachOrdered! Mimo to możesz później zdecydować o zmianie strumienia na równoległy i Twój kod zostanie zepsuty. Również podczas korzystania z forEachOrdered czytnik Twojego kodu widzi komunikat: "zamówienie ma tutaj znaczenie". W ten sposób dokumentuje twój kod lepiej.

Należy również zauważyć, że w przypadku strumieni równoległych forEach jest wykonywany nie tylko w porządku nie-deterministycznym, ale można go również wykonywać jednocześnie w różnych wątkach dla różnych elementów (co nie jest możliwe z forEachOrdered).

Wreszcie zarówno forEach/forEachOrdered są rzadko przydatne. W większości przypadków konieczne jest uzyskanie pewnego wyniku, a nie tylko efektu ubocznego, dlatego bardziej odpowiednie powinny być operacje takie jak: reduce lub collect. Wyrażanie redukcji przez operację za pomocą forEach jest zwykle uważane za zły styl.

+6

"Wreszcie zarówno dlaEach/forEachOrdered są rzadko przydatne". Nie mogłem się więcej zgodzić. Wygląda na to, że te metody są nadmiernie wykorzystywane. – Tunaki

+0

Dzięki za odpowiedź. ale to nie jest prawdziwy przykład życia. Właśnie uczę się java 8 – gstackoverflow

+0

Dlaczego semantycznie konieczne jest użycie 'forEachOrdered' w tym kodzie? – RealSkeptic