programing

Java 8에서 유형을 변환하는 축소 방법을 위해 결합기가 필요한 이유는 무엇입니까?

prostudy 2022. 6. 15. 20:55
반응형

Java 8에서 유형을 변환하는 축소 방법을 위해 결합기가 필요한 이유는 무엇입니까?

는 그 역할이 할 수 combinerreduce★★★★★★ 。

예를 들어, 다음 코드는 컴파일되지 않습니다.

int length = asList("str1", "str2").stream()
            .reduce(0, (accumulatedInt, str) -> accumulatedInt + str.length());

컴파일 오류: (인수가 일치하지 않습니다.int는 java.lang으로 변환할 수 없습니다.문자열)

이 코드는 컴파일 됩니다.

int length = asList("str1", "str2").stream()  
    .reduce(0, (accumulatedInt, str ) -> accumulatedInt + str.length(), 
                (accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2);

결합기 메서드는 병렬 스트림에서 사용되는 것으로 알고 있습니다.이 예에서는 2개의 중간 누적 int를 합산하고 있습니다.

그러나 첫 번째 예는 결합기 없이 컴파일되지 않는 이유나 결합기가 문자열에서 int로의 변환을 해결하는 방법은 두 개의 int를 합친 것에 불과하기 때문에 이해할 수 없습니다.

누가 이걸 밝혀줄 수 있나요?

Eran의 답변은 두 개의 아그 버전과 세 개의 아그 버전의 차이점을 설명했습니다.reduce가 줄인다는 Stream<T>로로 합니다.T는 줄인다.Stream<T>로로 합니다.U '나다', '어울리다', '어울리다', '어울리다', '어울리다'를 줄일 때 되지 않았습니다Stream<T>로로 합니다.U.

Streams API의 설계 원칙 중 하나는 순차 스트림과 병렬 스트림 간에 API가 달라서는 안 된다는 것입니다. 즉, 특정 API가 순차적으로 또는 병렬로 스트림이 올바르게 실행되지 않도록 해야 한다는 것입니다.람다에 올바른 속성(관련성, 비간섭성 등)이 있는 경우 스트림을 순차적으로 또는 병렬로 실행하면 동일한 결과가 나타납니다.

먼저 2개의 arg 버전의 reduction에 대해 설명하겠습니다.

T reduce(I, (T, T) -> T)

시퀀셜 실장은 간단합니다. 값 ID 。I결과를 얻기 위해 0번째 스트림 요소로 "자극"됩니다.이 결과는 다른 결과를 얻기 위해 첫 번째 스트림 요소와 함께 축적되며, 두 번째 스트림 요소와 함께 축적되는 등 계속됩니다.마지막 요소가 누적된 후 최종 결과가 반환됩니다.

병렬 구현은 스트림을 세그먼트(segment)로 분할함으로써 시작됩니다.각 세그먼트는 위에서 설명한 순서대로 자체 스레드에 의해 처리됩니다.N개의 스레드가 있으면 N개의 중간 결과가 됩니다.이것들은 하나의 결과로 줄일 필요가 있다.각 중간 결과는 T타입이고 여러 개의 결과가 있기 때문에 N개의 중간 결과를 단일 결과로 줄이기 위해 동일한 누적 함수를 사용할 수 있습니다.

이번에는 아그()를 줄이는 Stream<T>로로 합니다.U다른 언어에서는 이것을 "폴드" 또는 "폴드-레프트" 연산이라고 부르기 때문에 저는 이것을 여기라고 부릅니다.Java에는 존재하지 않습니다.

U foldLeft(I, (U, T) -> U)

값(ID ')에해 주세요.I)))))))))

foldLeft.reduce중간값이 T형이 아닌 U형이라는 점을 제외한다.가정적)foldRight조작은 왼쪽에서 오른쪽으로가 아니라 오른쪽에서 왼쪽으로 수행된다는 점을 제외하면 비슷합니다.)

이번에는 병행해서 .foldLeft세그먼트그런 다음 각 N개의 스레드가 세그먼트 내의 T값을 U형의 N개의 중간값으로 줄일 수 있습니다.제제어 떻떻 ?? ???어떻게 하면 유형 U의 N개의 값을 유형 U의 단일 결과로 줄일 수 있을까요?

U형의 여러 중간 결과를 U형의 단일 결과로 결합하는 또 다른 함수가 누락되어 있습니다. 두 개의 U 값을 하나로 결합하는 함수가 있다면 위의 원래 감소와 마찬가지로 임의의 수의 값을 1로 줄이는 것으로 충분합니다.따라서 다른 유형의 결과를 제공하는 축소 연산에는 두 가지 기능이 필요합니다.

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를 제공한다는 위에서 설명한 설계 원칙과 충돌합니다.

저는 낙서나 화살표를 좋아하기 때문에 컨셉을 명확하게 하는...시작합시다!

문자열에서 문자열로(시퀀셜 스트림)

4개의 스트링이 있다고 가정해 봅시다.목표는 이러한 스트링을 하나로 연결하는 것입니다.기본적으로는 타입으로 시작해서 같은 타입으로 끝납니다.

이를 실현하기 위해서는

String res = Arrays.asList("one", "two","three","four")
        .stream()
        .reduce("",
                (accumulatedStr, str) -> accumulatedStr + str);  //accumulator

이를 통해 무슨 일이 일어나고 있는지 시각화할 수 있습니다.

여기에 이미지 설명 입력

누적기 함수는 (빨간색) 스트림의 요소를 단계별로 최종 감소(녹색) 값으로 변환합니다.는 단순히 '어큐뮬레이터'를 합니다.StringString.

문자열에서 int(병렬 스트림)로

동일한 4개의 문자열이 있다고 가정합니다.새로운 목표는 문자열의 길이를 합산하는 것이며 스트림을 병렬화하는 것입니다.

필요한 것은 다음과 같습니다.

int length = Arrays.asList("one", "two","three","four")
        .parallelStream()
        .reduce(0,
                (accumulatedInt, str) -> accumulatedInt + str.length(),                 //accumulator
                (accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2); //combiner

그리고 이것은 이 세상에서 일어나는 일들의 도식입니다.

여기에 이미지 설명 입력

(a 기 ( ( ( ( ( (aaaaaa(a))BiFunction)를 사용하면, 데이터 베이스의String에 대한 데이터int데이터. 스트림의 평행성이기 때문에 두 개의 (빨간색) 부분으로 나누어져 있으며, 각각은 서로 독립적으로 정교하게 설계되어 동일한 수의 부분(주황색) 결과를 생성합니다.부분 병합 규칙을 제공하려면 결합기를 정의해야 합니다.int결승(녹색)에 진출합니다.int하나.

문자열에서 int(시퀀셜 스트림)로

스트림을 병렬화하고 싶지 않다면 어떻게 해야 할까요?어쨌든 결합기를 제공해야 하지만, 부분적인 결과가 나오지 않기 때문에 절대 호출되지 않을 것입니다.

의 2가지 및 3가지 인수 버전reduce사용하려고 했던 것과 같은 타입을 사용할 수 없습니다.accumulator.

두 가지 주장reduce는 다음과 같이 정의됩니다.

T reduce(T identity,
         BinaryOperator<T> accumulator)

당신의 경우 T는 String이므로BinaryOperator<T>는 2개의 String 인수를 받아들이고 String을 반환해야 합니다.그러나 int와 String을 전달하면 컴파일 오류가 발생합니다.argument mismatch; int cannot be converted to java.lang.String사실 여기서도 ID값으로0을 건네주는 것은 잘못이라고 생각합니다.String이 필요하기 때문입니다(T).

또한 이 버전은 T의 스트림을 줄이고 T를 반환하므로 String의 스트림을 int로 줄이는 데 사용할 수 없습니다.

세 가지 주장reduce는 다음과 같이 정의됩니다.

<U> U reduce(U identity,
             BiFunction<U,? super T,U> accumulator,
             BinaryOperator<U> combiner)

이 경우 U는 Integer, T는 String이므로 이 메서드는 String 스트림을 Integer로 줄입니다.

를 위해BiFunction<U,? super T,U>누산기는 두 가지 다른 유형(U 및 ? super T)의 매개 변수를 전달할 수 있습니다. 이 경우 Integer와 String입니다.또한 ID 값 U에는 Integer를 사용할 수 있으므로 0을 전달해도 됩니다.

원하는 것을 달성하기 위한 또 다른 방법:

int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
            .reduce(0, (accumulatedInt, len) -> accumulatedInt + len);

여기서 스트림의 유형은 다음 반환 유형과 일치합니다.reduce의 2가지 파라미터 버전을 사용할 수 있습니다.reduce.

물론 사용할 필요는 없습니다.reduce전혀:

int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
            .sum();

병렬로 실행할 수 없기 때문에 결합기 없이 두 가지 다른 유형을 사용하는 축소 버전은 없습니다(이것이 왜 필요한지 확실하지 않음).어큐뮬레이터는 연관성이 있어야 하기 때문에 이 인터페이스는 다음과 같은 이유로 거의 사용되지 않습니다.

list.stream().reduce(identity,
                     accumulator,
                     combiner);

다음과 같은 결과를 얻을 수 있습니다.

list.stream().map(i -> accumulator(identity, i))
             .reduce(identity,
                     combiner);

언급URL : https://stackoverflow.com/questions/24308146/why-is-a-combiner-needed-for-reduce-method-that-converts-type-in-java-8

반응형