[java] Java 8 Stream API에서 peek () 및 allMatch ()가 함께 작동하는 방법

다음과 같이 peek 메소드의 Java 8 Stream API에 대한 퀴즈를 찾았습니다.

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

출력은

Fred
Jim

이 스트림이 어떻게 작동하는지 혼란 스럽습니까? 내 예상 결과는

Fred
Jim
Sheila

peek () 메서드는 중간 작업이며 Stream의 각 요소를 처리합니다. 누구든지 이것을 설명 할 수 있습니까?



답변

단락이라고 알려진 스트림 최적화입니다. 기본적으로 최종 결과를 알 때 수행 할 필요가 없기 때문에 스트림에서 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"))특정 알려져있다. 이후 파이프 라인에 어떤 값이 나오는지는 중요하지 않습니다. “F”로 시작"Jim" 하는 모든 값이 false 임을 알고 있습니다.

이것은 peek/ allMatch조합 에만 국한되지 않으며 여러 개의 중간 및 터미널 단락 작업이 있습니다. java.util.stream패키지 문서 상태 :

또한 일부 작업은 단락 작업으로 간주됩니다. 무한 입력이 표시 될 때 결과적으로 유한 스트림을 생성 할 수있는 경우 중간 작동이 단락됩니다. 무한 입력이 표시 될 때 유한 시간 내에 종료 될 수있는 경우 터미널 작동이 단락됩니다. 파이프 라인에서 단락 동작을하는 것은 무한 스트림의 처리가 유한 시간 내에 정상적으로 종료하기위한 필수 조건이지만 충분하지는 않다.

이것을 유한 스트림으로 확장하고 단락 작업은 예제의 경우처럼 불필요한 파이프 라인 단계의 실행을 방지합니다.


답변

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • 처음부터 Fred인쇄됩니다. 너무 일치
  • 두 번째부터 Jim인쇄됩니다. 일치하지 않으므로 “모두 일치하지 않기”때문에 allMatch가 종료됩니다.
  • 따라서 마지막 항목은 스트림에서 소비되지 않았습니다.

답변

이 방법에 대한 문서 는 다음과 같이 peek말합니다 (강조 광산).

이 스트림의 요소로 구성된 스트림을 리턴 하고 결과 스트림에서 요소가 소비 될 때 각 요소에 대해 제공된 조치를 추가로 수행합니다 .

따라서이 경우에는 peek볼 수 없습니다 "Sheila"그 값은 스트림에서 소비되지 않기 때문에. "Jim"소비 되 자마자 결과 .allMatch(s -> s.startsWith("F"))는 이미 알려진 것으로 false스트림에서 더 이상 요소를 소비 할 필요가 없습니다.


답변

allMatch ()의 Java Doc에 따라 :

이 스트림의 모든 요소가 제공된 술어와 일치하는지 여부를 리턴합니다. 결과를 결정하는 데 필요하지 않은 경우 모든 요소에 대한 술어를 평가할 수 없습니다. 스트림이 비어 있으면 {@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이므로 스트림이 완전히 처리되었습니다.


답변