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

**** для каждого заказа с использованием параллельного ****

сушила митталь