Java 8에서 도입된 Stream의 reduce() 사용 방법 및 예제를 소개합니다.
1. Stream.reduce()
Stream.reduce(accumulator)
함수는 Stream의 요소들을 하나의 데이터로 만드는 작업을 수행합니다.
예를 들어, Stream에서 1부터 10까지 숫자가 전달될 때, 이 값을 모두 합하여 55의 결과가 리턴되도록 만들 수 있습니다. 여기서 연산을 수행하는 부분은 accumulator 함수이며, 직접 구현해서 인자로 전달해야 합니다.
아래는 reduce()
를 사용하여 Stream에서 전달되는 요소들의 숫자를 모두 합하는 예제입니다.
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));
Output:
sum: 55
위의 예제를 설명하면서 reduce()
의 동작 방식에 대해서 소개하겠습니다.
reduce()
는 인자로 BinaryOperator 객체를 받는데, BinaryOperator는 T 타입의 인자 두개를 받고 T 타입의 객체를 리턴하는 함수형 인터페이스입니다.
BinaryOperator는 (total, n) -> total + n
와 같은 형식으로 인자가 전달되는데요. Stream의 1이 전달될 때, total(0) + n(1) = 1
와 같이 계산되고, 여기서 리턴되는 1이 다음에 Stream에서 2가 전달될 때 total로 전달됩니다. 따라서, total(1) + n(2) = 3
이 됩니다.
다시 정리하면 아래와 같이 연산되면서, 마지막에는 1에서 10까지의 숫자를 더한 55가 리턴됩니다.
- total(0) + n(1) = 1
- total(1) + n(2) = 3
- total(3) + n(3) = 6
- total(6) + n(4) = 10
- total(10) + n(5) = 15
- total(15) + n(6) = 21
- total(21) + n(7) = 28
- total(28) + n(8) = 36
- total(36) + n(9) = 45
- total(45) + n(10) = 55
1.1 메소드 레퍼런스로 구현
(x, y) -> x + y
와 같이 합을 계산하는 함수는, JDK에서 Integer.sum(a, b)
라는 기본 함수를 제공합니다.
여기서 메소드 레퍼런스를 이용하면, Integer::sum
처럼 더 짧은 코드로 동일한 결과를 리턴하는 코드를 구현할 수 있습니다.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> sum = numbers.reduce(Integer::sum);
sum.ifPresent(s -> System.out.println("sum: " + s));
2. 초기값이 있는 Stream.reduce()
위의 예제에서는 total의 초기 값이 0이였습니다.
하지만 Stream.reduce(init, accumulator)
처럼 초기 값을 인자로 전달할 수 있습니다.
위의 예제에서 초기 값이 10으로 설정하면, '10 + 1 + 2 + 3... 10'과 같이 연산을 합니다.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = numbers.reduce(10, (total, n) -> total + n);
System.out.println("sum: " + sum);
Output:
sum: 65
3. reduce()의 병렬 처리
Stream.parallel()
은 Stream 연산을 병렬 처리로 수행하도록 합니다. 즉, parallel()
과 함께 reduce()
를 사용하면 순차적으로 연산을 수행하지 않고 여러개의 연산을 동시에 진행하고, 그 작업들을 다시 병합하여 최종적으로 1개의 결과를 생성합니다.
예를 들어, (1 + 2) + (3 + 4) + ... + (9 + 10)
처럼 두개씩 묶어서 먼저 계산하고, 그 결과들을 다시 계산할 수 있습니다.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = numbers.parallel().reduce(0, (total, n) -> total + n);
System.out.println("sum: " + sum);
Output:
sum: 55
하지만 빼기 연산의 경우 병렬처리는 순차적인 처리(병렬이 아닌)와 결과가 다릅니다.
아래 코드를 실행해보면 -55가 아니라 -5가 리턴됩니다.
결과가 다른 이유는 (1 - 2) - (3 - 4) - ... - (9 - 10)
처럼 연산이 수행되면서 순차적으로 연산하는 것과 결과가 달라지기 때문입니다.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = numbers.parallel().reduce(0, (total, n) -> total - n);
System.out.println("sum: " + sum);
Output:
sum: -5
병렬 처리 과정에서 reduce()
를 사용할 때는 위와 같은 문제가 없는지 확인을 해야 합니다.
4. 병렬 처리에서 reduce()는 순차적으로 처리
병렬처리에서 연산 순서에 따라 발생하는 문제를 해결하기 위해, 아래 예제와 같이 다른 규칙을 추가할 수 있습니다.
위의 예제와 비교해보면 (total1, total2) -> total1 + total2
가 추가되었는데, 병렬로 처리된 결과들의 관계를 나타냅니다.
다시 설명하면, 첫번째 연산과 두번째 연산은 합해야 한다는 규칙을 추가한 것인데요. 이렇게 규칙을 추가하면, 첫번째 연산의 결과가 다음 연산에 영향을 주기 때문에 reduce()
는 작업을 나눠서 처리할 수 없게 됩니다.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = numbers.reduce(0,
(total, n) -> total - n,
(total1, total2) -> total1 + total2);
System.out.println("sum: " + sum);
Output:
sum: -55
Related Posts
- Java - Unsupported class file major version 61 에러
- Java - String.matches()로 문자열 패턴 확인 및 다양한 예제 소개
- Java - 문자열 공백제거 (trim, replace)
- Java - replace()와 replaceAll()의 차이점
- Java - ArrayList 초기화, 4가지 방법
- Java - 배열 정렬(Sorting) (오름차순, 내림차순)
- Java - 문자열(String)을 비교하는 방법 (==, equals, compare)
- Java - StringBuilder 사용 방법, 예제
- Java - 로그 출력, 파일 저장 방법 (Logger 라이브러리)
- Java IllegalArgumentException 의미, 발생 이유
- Java - NullPointerException 원인, 해결 방법
- Seleninum의 ConnectionFailedException: Unable to establish websocket connection 해결
- Java - compareTo(), 객체 크기 비교
- Java - BufferedWriter로 파일 쓰기
- Java - BufferedReader로 파일 읽기
- Java charAt() 함수 알아보기
- Java - BigInteger 범위, 비교, 연산, 형변환
- Java contains()로 문자(대소문자 X) 포함 확인
- Java - Set(HashSet)를 배열로 변환
- Java - 문자열 첫번째 문자, 마지막 문자 확인
- Java - 문자열 한글자씩 자르기
- Java - 문자열 단어 개수 가져오기
- Java - 1초마다 반복 실행
- Java - 배열을 Set(HashSet)로 변환
- Java - 여러 Set(HashSet) 합치기
- Java - 명령행 인자 입력 받기
- Java - 리스트 역순으로 순회, 3가지 방법
- Java - 특정 조건으로 리스트 필터링, 3가지 방법
- Java - HashMap 모든 요소들의 합계, 평균 계산
- Java - 특정 조건으로 HashMap 필터링
- Java - 싱글톤(Singleton) 패턴 구현
- Java - 숫자 왼쪽에 0으로 채우기
- Java - String 배열 초기화 방법
- Java - 정렬된 순서로 Map(HashMap) 순회
- Java - HashMap에서 key, value 가져오기