[JAVA]Stream 리듀싱 활용

2022. 10. 13. 15:54 JAVA BASIC/Lambda&Stream(람다와 스트림)

메뉴에서 칼로리가 가장 높은 요리는? 같이 스트림 요소를 조합해서 더 복잡한 질의를 표현하는 방법에 대해 알아보자.

이러한 질의를 수행하려면 Integer 같은 결과가 나올 때까지 스트림의 모든 요소를 반복적으로 처리해야 한다. 이런 질의를 리듀싱 연산(모든 스트림 요소를 처리해서 값으로 도출하는)이라고 한다.

1. 요소의 합

// for-each 사용
int sum = 0;
for (int x : numbers) {
        sum += x;
}

// stream 사용
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int sum = numbers.stream().reduce(0, Integer::sum);

reduce는 두 개의 인수를 갖는다.

  • 초깃값
  • 스트림의 두 요소를 합쳐서 하나의 값으로 만드는 데 사용할 람다

 

람다의 첫 번째 파라미터(a)에 0이 사용, 스트림에서 4를 소비해서 두 번째 파라미터(b)로 사용

0 + 4의 결과인 4가 새로운 누적값(accumulated value)이 됨. 누적값으로 람다를 다시 호출하여 반복

초깃값 없음

초기값을 받지 않도록 오버르드된 reduce도 있다. 그러나 이 reduce는 Optional 객체를 반환한다.

Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

스트림에 아무 요소도 없는 경우 합계가 없음을 가리킬 수 있도록 Optional 객체로 감싼 결과를 반환한다.

2. 최댓값과 최솟값

두 요소에서 최댓값을 반환하는 람다만 있으면 최댓값을 구할 수 있다.

reduce 연산은 새로운 값을 이용해서 스트림의 모든 요소를 소비할 때 까지 람다를 반복 수행하면서 최대값을 생상한다.

Optional<Integer> max = numbers.stream().reduce(Integer::max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);

 

reduce 메서드의 장점과 병렬화

for-each or iterator vs stream reduce

reduce를 이용하면 내부 반복이 추상화되면서 내부 구현에서 병렬로 redcue를 실행할 수 있게 된다.

만약에 반복적인 합계(iterator)를 이용한다면 sum 변수를 공유해야하므로 쉽게 병렬하기가 어려워 진다. ( + 입력 분할, 분할된 입력 더함, 더한 값을 합침).

stream reduce를 이용하면 parallelStream()으로 병렬 수행을 간단하게 할 수 있음.

 

출처 : 모던자바인액션

출처: https://cornswrold.tistory.com/544 [평범한개발자노트:티스토리]