, 둘다의 답변 의 2 및 3 ARG ARG 버전 차이 기재된 reduce
전자가 감소 시킴에 Stream<T>
에 T
후자는 감소하는 반면 Stream<T>
에이 U
. 그러나 실제로로 축소 Stream<T>
할 때 추가 결합기 기능의 필요성을 설명하지는 않았습니다 U
.
Streams API의 디자인 원칙 중 하나는 API가 순차적 스트림과 병렬 스트림간에 다르지 않아야하거나 다른 방법으로 특정 스트림이 순차적으로 또는 병렬로 스트림이 올바르게 실행되는 것을 막지 않아야한다는 것입니다. 람다에 올바른 속성 (연관, 비 간섭 등)이있는 경우 순차적으로 또는 병렬로 실행되는 스트림은 동일한 결과를 제공해야합니다.
먼저 두 가지 버전의 축소를 고려해 보겠습니다.
T reduce(I, (T, T) -> T)
순차적 구현은 간단합니다. 항등 값 I
은 0 번째 스트림 요소와 함께 "누적"되어 결과를 제공합니다. 이 결과는 제 1 스트림 요소와 함께 누적되어 다른 결과를 제공하며, 결과적으로 제 2 스트림 요소와 함께 누적되는 식으로 진행된다. 마지막 요소가 누적 된 후 최종 결과가 반환됩니다.
병렬 구현은 스트림을 세그먼트로 분할하여 시작합니다. 각 세그먼트는 위에서 설명한 순서대로 자체 스레드에 의해 처리됩니다. 이제 N 개의 스레드가 있으면 N 개의 중간 결과가 나타납니다. 이것들은 하나의 결과로 줄여야합니다. 각 중간 결과는 유형 T이고 여러 개의 결과가 있으므로 동일한 누산기 함수를 사용하여 N 개의 중간 결과를 단일 결과로 줄일 수 있습니다.
이제 감소 가상의 두 인수 감소 동작을 살펴 보자 Stream<T>
에를 U
. 다른 언어에서는 이것을 "접음" 또는 "왼쪽 접힘"조작이라고하므로 여기에이를 호출합니다. Java에는 존재하지 않습니다.
U foldLeft(I, (U, T) -> U)
ID 값 I
은 U 유형입니다.
순차 버전은 중간 값이 T 유형 대신 U 유형이라는 점을 제외하고 foldLeft
는 순차 버전과 reduce
같습니다. 그러나 그렇지 않으면 동일합니다. (가설 foldRight
작업은 왼쪽에서 오른쪽 대신 오른쪽에서 왼쪽으로 수행된다는 점을 제외하면 비슷합니다.)
이제의 병렬 버전을 고려하십시오 foldLeft
. 스트림을 세그먼트로 분할하여 시작하겠습니다. 그런 다음 각 N 스레드가 세그먼트의 T 값을 U 유형의 N 중간 값으로 줄 이도록 할 수 있습니다. 이제 무엇? U 유형의 N 값에서 U 유형의 단일 결과까지 어떻게 얻습니까?
누락 된 것은 U 유형의 여러 중간 결과를 U 유형의 단일 결과로 결합 하는 또 다른 함수입니다. 두 개의 U 값을 하나로 결합하는 함수가 있으면 값을 하나로 줄이면 충분합니다. 위의 원래 축소. 따라서 다른 유형의 결과를 제공하는 축소 연산에는 두 가지 기능이 필요합니다.
U reduce(I, (U, T) -> U, (U, U) -> U)
또는 Java 구문을 사용하십시오.
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
요약하면, 다른 결과 유형으로 병렬 축소를 수행하려면 T 요소를 중간 U 값으로 누적 하는 함수 와 중간 U 값을 단일 U 결과로 결합 하는 함수가 필요합니다 . 전환 유형이 아닌 경우 누산기 기능이 결합기 기능과 동일하다는 것이 밝혀졌습니다. 그렇기 때문에 같은 유형으로 줄이면 누산기 기능 만 있고 다른 유형으로 줄이면 별도의 누산기와 결합기 기능이 필요합니다.
마지막으로, 자바는 제공하지 않습니다 foldLeft
및 foldRight
그들이 본질적으로 순차적 인 작업의 특정 순서를 의미하기 때문에 작업. 이는 순차적 및 병렬 작업을 동일하게 지원하는 API를 제공하는 위에서 언급 한 설계 원칙과 충돌합니다.