ForEach vs forEachOrdered в Java 8 Stream
Я понимаю, что эти методы отличаются порядком выполнения, но во всем моем тесте я не могу добиться выполнения разных заказов.
Пример:
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));
Вывод:
forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC
Просьба привести примеры, когда 2 метода будут производить разные выходы.
Ответы
Ответ 1
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));
Вторая строка всегда будет выводить
Output:AAA
Output:BBB
Output:CCC
тогда как первая не гарантируется, так как заказ не сохраняется. forEachOrdered
будет обрабатывать элементы потока в порядке, указанном его источником, независимо от того, является ли поток последовательным или параллельным.
Цитата из forEach
Javadoc:
Поведение этой операции явно недетерминировано. Для параллельных поточных конвейеров эта операция не гарантирует уважения порядка вызова потока, так как это принесет пользу parallelism.
Когда forEachOrdered
Javadoc заявляет (внимание мое):
Выполняет действие для каждого элемента этого потока в порядке выполнения потока, если поток имеет определенный порядок регистрации.
Ответ 2
Хотя forEach
короче и выглядит красивее, я бы предложил использовать forEachOrdered
в любом месте, где порядок имеет значение, чтобы явно указать это. Для последовательных потоков forEach
, по-видимому, соответствует порядку и даже потоку API внутреннего кода использует forEach
(для потока, который, как известно, является последовательным), где семантически необходимо использовать forEachOrdered
! Тем не менее, вы можете позже решить изменить поток на параллельный, и ваш код будет нарушен. Также, когда вы используете forEachOrdered
, читатель вашего кода видит сообщение: "порядок здесь имеет значение". Таким образом, он лучше документирует ваш код.
Обратите также внимание на то, что для параллельных потоков forEach
выполняется не только в неопределенном порядке, но вы также можете выполнять его одновременно в разных потоках для разных элементов (что невозможно при использовании forEachOrdered
).
Наконец, оба forEach
/forEachOrdered
редко используются. В большинстве случаев вам действительно нужно произвести некоторый результат, а не только побочный эффект, поэтому операции, такие как reduce
или collect
, должны быть более подходящими. Выражение сокращающейся по характеру операции с помощью forEach
обычно считается плохим.
Ответ 3
Метод forEach() выполняет действие для каждого элемента этого потока. Для параллельного потока эта операция не гарантирует поддержания порядка потока.
Метод forEachOrdered() выполняет действие для каждого элемента этого потока, гарантируя, что каждый элемент обрабатывается в порядке встречи для потоков, которые имеют определенный порядок встречи.
возьмите пример ниже:
String str = "sushil mittal";
System.out.println("****forEach without using parallel****");
str.chars().forEach(s -> System.out.print((char) s));
System.out.println("\n****forEach with using parallel****");
str.chars().parallel().forEach(s -> System.out.print((char) s));
System.out.println("\n****forEachOrdered with using parallel****");
str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));
Выход:
**** для каждого без использования параллельного ****
сушила митталь
**** для каждого с использованием параллельного ****
Mihul Issltat
**** для каждого заказа с использованием параллельного ****
сушила митталь