Collection 의 합을 구하는 방법
Collection 의 합을 구하는 방법은 reduce
와 sum
두 가지가 존재합니다.
단, Stream 에서 sum()
을 사용하려면 IntStream, LongStream, DoubleStream
와 같은 기본형 (Primitive Type) 특화 스트림을 사용해야 합니다.
그래서 보통 mapToInt, mapToLong, mapToDouble
같은 메소드로 스트림을 변환시키고 사용합니다.
reduce
reduce(초기값, 연산)
형식으로 사용합니다.
초기값부터 시작하여 각 원소를 차례대로 순회하며 연산을 수행합니다.
이전 연산의 결과를 다음 초기값으로 넘기면서 연산의 결과를 누적해서 총 결과값을 구하는 메서드입니다.
int sum = Stream.of(1, 2, 3).reduce(0, Integer::sum);
sum
Stream 의 총합을 구하는 메서드입니다.
기본형 특화 스트림에서만 사용 가능합니다.
int sum = Stream.of(1, 2, 3).mapToInt(e -> e).sum();
그렇다면 합을 구할 때 어떤걸 사용할까?
처음 생각 할 때는 reduce
로 한번에 하는게 Stream 처리가 적어서 더 빠를거라고 생각했습니다.
가독성도 크게 차이 안납니다.
그런데 실제로 테스트 해보니 결과는 달랐습니다.
Test Code
public static void main(String[] args) {
Map<String, Integer> hashmap = new HashMap<>();
for (int i = 0; i < 10000000; i++) {
hashmap.put(i + "", i);
}
// for-loop 시간측정
long start1 = System.currentTimeMillis();
int sum1 = 0;
for (String key : hashmap.keySet()) {
sum1 += hashmap.get(key);
}
long end1 = System.currentTimeMillis();
// stream mapToInt 시간측정
long start2 = System.currentTimeMillis();
int sum2 = hashmap.values().stream().reduce(0, Integer::sum);
long end2 = System.currentTimeMillis();
// stream reduce 시간측정
long start3 = System.currentTimeMillis();
int sum3 = hashmap.values().stream().mapToInt(i -> i).sum();
long end3 = System.currentTimeMillis();
System.out.println("for-loop: " + (end1 - start1));
System.out.println("int reduce: " + (end2 - start2));
System.out.println("mapToInt: " + (end3 - start3));
}
Result
for-loop: 303
reduce: 368
mapToInt: 310
원인 & 결론
reduce
에는 박싱, 언박싱 비용이 들어갑니다.
내부적으로 합계를 계산하기 위해 Integer
를 int
형으로 언박싱 하고 다시 int -> Integer
로 박싱하는 과정이 숨겨져 있어서 시간이 더 오래 걸립니다.
그래서 reduce
의 성능이 더 느리니 IntStream
에서 제공하는 메서드가 있는 경우에는 해당 메서드를 사용하는 게 유용합니다.
Reference
'Language > Java' 카테고리의 다른 글
Java Stream count() 의 비밀 (0) | 2021.04.18 |
---|---|
Java 8 함수형 인터페이스 (Functional Interface) (1) | 2021.04.10 |
Mac OS Java (OpenJDK) 설치 및 버전 변경 (2) | 2021.03.08 |
[Java] Static (0) | 2020.09.19 |
[Java] Map, HashMap, LinkedHashMap (0) | 2020.04.25 |