, 둘다의 답변 의 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를 제공하는 위에서 언급 한 설계 원칙과 충돌합니다.