forEach проти forEachЗамовлено в Java 8 Stream


86

Я розумію, що ці методи відрізняються порядком виконання, але в усьому своєму тесті я не можу досягти іншого виконання замовлення.

Приклад:

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 методи дадуть різні результати.


Спробуйте, можливо, з паралельними потоками.
Пшемо

@Pshemo це єдино можливий варіант?
gstackoverflow

5
Невстановлений порядок не означає "гарантований інший порядок". Це просто означає неуточнене , що завжди передбачає можливість відповідати порядку зустрічі. Немає вбудованої функції перетасування.
Holger

Відповіді:


89
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

тоді як перший не гарантується, оскільки замовлення не зберігається. forEachOrderedwill обробляє елементи потоку в порядку, визначеному його джерелом, незалежно від того, є потік послідовним чи паралельним.

Посилання з forEachJavadoc:

Поведінка цієї операції явно недетерміноване. Для трубопроводів паралельного потоку ця операція не гарантує дотримання порядку зустрічі потоку, оскільки це призведе до жертви переваг паралелізму.

Коли forEachOrderedJavadoc стверджує (наголос на моєму):

Виконує дію для кожного елемента цього потоку в порядку зустрічі потоку, якщо потік має визначений порядок зустрічі.


6
Так, ти правий. Чи можливо це лише для паралельних потоків?
gstackoverflow

6
Навіть якби це стосувалося б лише зараз паралельних потоків - і я не кажу, що це робиться - воно все одно може зламатися в майбутньому, якщо деякі проміжні кроки будуть оптимізовані для використання переваг невпорядкованих потоків, наприклад, сортування може використовувати нестабільний алгоритм, якщо потік невпорядкований.
the8472

1
Тож немає сенсу використовувати forEachOrderedз parallel?
Bhushan

3
@BhushanPatil Так, це правильно. stackoverflow.com/questions/47336825/…
Сагар,

1
Використання forEachOrdered буде обробляти елемент за порядком, тоді використання паралельних потоків втратить переваги паралелізму. Будь ласка, підкажіть.
Діпак

30

Хоча forEachкоротший і виглядає симпатичнішим, я пропоную використовувати forEachOrderedв будь-якому місці, де має значення порядок, щоб чітко це вказати. Для послідовних потоків, forEachздається, поважає порядок і навіть використовує внутрішній код API потоку forEach(для потоку, який, як відомо, є послідовним), де це семантично необхідно використовувати forEachOrdered! Проте пізніше ви можете вирішити змінити свій потік на паралельний, і ваш код буде зламаний. Також коли ви використовуєтеforEachOrdered зчитувач вашого коду, бачить повідомлення: "порядок тут важливий". Таким чином, він краще документує ваш код.

Зауважте також, що для паралельних потоків forEachне тільки виконується в недетермінованому порядку, але ви також можете одночасно виконувати його в різних потоках для різних елементів (що неможливо з forEachOrdered).

Нарешті, обидва forEach/ forEachOrderedрідко бувають корисними. У більшості випадків вам насправді потрібно отримати якийсь результат, а не лише побічний ефект, отже операції, подібні reduceабо collectповинні бути більш придатними. Вираження скорочувальної природи за допомогою forEachзвичайно вважається поганим стилем.


7
"Нарешті, обидва forEach / forEachOrdered рідко бувають корисними". Я не міг погодитися з тим. Здається, ці методи надмірно використовуються.
Tunaki

Дякую за відповідь. але це не приклад із реального життя. Я просто вивчаю java 8
gstackoverflow

Чому семантично необхідно використовувати forEachOrderedв цьому коді?
RealSkeptic

1
@RealSkeptic, це вказаний користувачем потік (переданий в flatMap). Його можна замовити, тому його потрібно розмістити в отриманому потоці в тому ж порядку.
Тагір Валєєв

2
@RealSkeptic, ти справжній скептик! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)повертає true, отже порядок для результуючого потоку повинен бути визначений. Якщо ви вважаєте, що документація JDK повинна прямо про це говорити, сміливо надсилайте помилку.
Тагір Валєєв

15

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

Вихід:

****forEach without using parallel****

sushil mittal

****forEach with using parallel****

mihul issltat

****forEachOrdered with using parallel****

sushil mittal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.