Як peek () та allMatch () працюють разом у Java 8 Stream API


10

Як я показав нижче, я знайшов тест про API API 8 для потоку Java 8 Stream

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

Вихід є

Fred
Jim

Мене бентежить, як працює цей потік? Мій очікуваний результат повинен бути

Fred
Jim
Sheila

Метод peek () - це проміжна операція, і він обробляє кожен елемент у Stream. Хтось може мені це пояснити.

Відповіді:


10

Це оптимізація потоку, відома як коротке замикання. По суті, що трапляється, це allMatchперешкоджає виконанню зайвих проміжних операцій на потоці, оскільки немає сенсу їх виконувати, коли відомий кінцевий результат.

Це так, ніби це сталося:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

Коли "Jim".startsWith("F")оцінюється, результат allMatch(s -> s.startsWith("F"))відомий напевно. Не має значення, які значення надходять у конвеєр після "Jim", ми знаємо, що всі значення, що починаються з "F", помилкові

Це не властиво peek/ allMatchкомбінації, є декілька проміжних та кінцевих операцій короткого замикання. java.util.streamДокументи пакету :

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

Розширюйте це на кінцеві потоки, а операції з коротким замиканням унеможливлюють виконання непотрібних кроків трубопроводу, як у випадку з вашим прикладом.


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • Вперше через, Fredдрукується. Це так відповідає
  • Вдруге через, Jimдрукується. Він не відповідає, тому allMatch припиняється, оскільки "Усі не відповідали"
  • Тож останній предмет не був спожитий із потоку.

3

У документах для peekметоду говорить (курсив мій):

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

Тож у цьому випадку peekвін не бачить, "Sheila"оскільки це значення не споживається з потоку. Як тільки "Jim"було спожито, результат .allMatch(s -> s.startsWith("F"))вже відомий false, тому немає необхідності споживати більше елементів із потоку.


1

Відповідно до Java Doc Of allMatch ():

Повертає, чи всі елементи цього потоку відповідають наданому предикату. Не може оцінювати присудок щодо всіх елементів, якщо це не потрібно для визначення результату. Якщо потік порожній, повертається {@code true}, а предикат не оцінюється.

@apiNote

Цей метод оцінює універсальне кількісне визначення присудка над елементами потоку (для всіх x P (x)). Якщо потік порожній, сказано, що кількісне визначення є задоволеним і завжди {@code true} (незалежно від P (x)).

предикат застосовувати до елементів цього потоку @return {@code true}, якщо будь-які елементи потоку відповідають наданому предикату або потік порожній, інакше {@code false}

У вашому випадку:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

Подальше оцінювання не відбуватиметься, оскільки XP (X) = false

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

Вихід:

Fred
Finda
Fish
Result true

Тут потік обробляється повністю, тому що xP (x) = true з кожного елемента

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