HOME > java > java8

Java8의 Stream reduction 사용 방법

JSFollow09 Oct 2018

Reduction

Stream의 데이터를 변환하지 않고, 더하거나 빼는 등의 연산을 수행하여 하나의 값으로 만든다면 reduce를 사용할 수 있습니다.

예를 들면, 아래 코드는 1 + 2 + ... + 10의 합을 출력해줍니다.

Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> sum = numbers.reduce((x, y) -> x + y);
sum.ifPresent(s -> System.out.println("sum: " + s));
#결과
sum: 55

reduce()의 param으로 (total, n) -> total + n가 전달되고, reduce는 a1, a2, a3, a4...의 stream을 a1 + a2 + a3 + a4...로 연산을 수행합니다. 첫번째로 total=a1, n=a2가 되고, 두번째로 total=(a1+a2), n=a3가 됩니다.

함수를 정의하지 않고 Integer::sum을 사용해도 위와 동일한 결과를 출력합니다.

Stream<Integer> numbers2 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> sum2 = numbers2.reduce(Integer::sum);
sum2.ifPresent(s -> System.out.println("sum2: " + s));
#결과
sum2: 55

초기값 있는 Reduction

위와 동일한 동작을 하지만 초기값을 지정해줄 수 있습니다. 첫번째 param으로 초기값을 넘겨주면 됩니다. 초기값이 없는 위와 유사하게 '10 + 1 + 2 + ... 10'으로 연산됩니다.

Stream<Integer> numbers3 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum3 = numbers3.reduce(10, (total, n) -> total + n);
System.out.println("sum3: " + sum3);
#결과
sum3: 65

병렬처리 & Reduction

parallel()을 사용하면 병렬처리로 연산을 수행할 수 있습니다. 순차적으로 연산을 수행하지 않고 여러개의 작업을 병렬로 처리합니다. (1 + 2) + (3 + 4) + ... + (9 + 10)처럼 병렬적으로 처리됩니다.

Stream<Integer> numbers4 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum4 = numbers4.parallel().reduce(0, (total, n) -> total + n);
System.out.println("sum4: " + sum4);
#결과
sum4: 55

하지만 -(마이너스) 연산인 경우 병렬처리는 순차처리와 결과가 다릅니다. 아래 코드를 보면 결과가 -55가 아니라 -5가 됩니다. (1 - 2) - (3 - 4) - ... - (9 - 10)처럼 연산의 순서가 어떻게 되냐에 따라서 결과가 순차처리와 다르게 됩니다.

Stream<Integer> numbers5 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum5 = numbers5.parallel().reduce(0, (total, n) -> total - n);
System.out.println("sum5: " + sum5);
#결과
sum5: -5

순서 있는 병렬처리 Reduction

병렬처리에서 연산 순서에 따라 발생하는 문제를 해결하기 위해 다음과 같이 다른 규칙을 추가할 수 있습니다. param으로 (total1, total2) -> total1 + total2를 추가하였는데 병렬처리된 결과의 관계를 나타냅니다. 첫번째 연산과 두번째 연산은 합해야 한다는 규칙을 정의하여, 연산결과가 순차처리와 동일하게 됩니다.

Stream<Integer> numbers6 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum6 = numbers6.reduce(0,
        (total, n) -> total - n,
        (total1, total2) -> total1 + total2);
System.out.println("sum6: " + sum6);
sum6: -55