Java Collector 활용 완벽 이해하기
Java Stream API를 사용하다 보면 거의 반드시 등장하는 것이 바로:
Collector
입니다.
특히 실무에서는:
- 리스트 변환
- 그룹핑
- 통계 계산
- Map 변환
- 데이터 집계
전부 Collector 기반으로 처리하는 경우가 많습니다.
예:
list.stream()
.collect(Collectors.toList());
이 코드가 바로 Collector 사용 예시입니다.
처음에는 단순히:
Stream 결과를 List로 바꾸는 거?
처럼 보이지만,
실제로 Collector는:
- Stream 최종 수집 전략
- mutable reduction
- grouping
- downstream collector
- 병렬 Stream 수집
까지 연결되는 매우 중요한 Stream 핵심 개념입니다.
이번 글에서는:
- Collector란?
- collect() 동작 원리
- toList()
- groupingBy()
- partitioningBy()
- mapping()
- downstream collector
- 병렬 수집 구조
까지 깊게 정리해보겠습니다.
1. Collector란?
Collector 는:
Stream 데이터를 원하는 형태로 수집하는 전략 객체
입니다.
2. 왜 필요할까?
Stream은 기본적으로:
데이터 흐름(pipeline)
입니다.
즉 마지막에:
결과를 어디에 담을지
결정 필요.
3. collect()란?
대표 최종 연산.
.collect(...)
4. 역할
Stream 결과를 수집
합니다.
5. 가장 기본 예시
List<String> result =
stream.collect(Collectors.toList());
6. 의미
Stream 요소들을 List로 모음
입니다.
7. Collectors 클래스
Collectors 는:
다양한 Collector 생성 유틸 클래스
입니다.
8. 가장 많이 사용하는 Collector
| toList | List 수집 |
| toSet | Set 수집 |
| toMap | Map 수집 |
| groupingBy | 그룹핑 |
| partitioningBy | 분할 |
| joining | 문자열 결합 |
| counting | 개수 계산 |
9. toList()
가장 기본.
.collect(Collectors.toList())
10. 동작
Stream → List 변환
입니다.
11. 예시
List<Integer> result =
list.stream()
.filter(x -> x > 10)
.collect(Collectors.toList());
12. toSet()
.collect(Collectors.toSet())
13. 특징
중복 제거
가능.
14. joining()
문자열 결합.
15. 예시
String result =
list.stream()
.collect(Collectors.joining(", "));
16. 결과
A, B, C
형태.
17. counting()
개수 계산.
18. 예시
long count =
list.stream()
.collect(Collectors.counting());
19. 사실상 count()와 유사
하지만 downstream collector에서 매우 중요.
20. groupingBy()
실무에서 매우 중요합니다.
21. 의미
특정 기준으로 그룹화
입니다.
22. 예시
Map<String, List<User>> result =
users.stream()
.collect(
Collectors.groupingBy(
User::getDepartment
)
);
23. 결과 구조
부서별 User 목록
Map 생성.
24. 예시 결과
{
"DEV": [...],
"HR": [...]
}
25. groupingBy 내부 동작
실제로는:
key 생성
↓
Map bucket 저장
↓
List 누적
구조.
26. partitioningBy()
groupingBy와 유사하지만:
boolean 기준 2분할
전용.
27. 예시
Map<Boolean, List<Integer>> result =
list.stream()
.collect(
Collectors.partitioningBy(
x -> x > 10
)
);
28. 결과
true -> 조건 만족
false -> 조건 불만족
29. toMap()
매우 중요.
30. 예시
Map<Long, User> map =
users.stream()
.collect(
Collectors.toMap(
User::getId,
user -> user
)
);
31. 의미
id 기반 Map 생성
입니다.
32. 그런데 주의점
매우 중요.
중복 key 발생 시:
IllegalStateException
발생 가능.
33. 해결 방법
merge function 추가.
Collectors.toMap(
User::getId,
user -> user,
(a, b) -> a
)
34. downstream collector란?
매우 중요합니다.
35. 의미
Collector 내부에 또 Collector 사용
하는 것.
36. 예시
Collectors.groupingBy(
User::getDepartment,
Collectors.counting()
)
37. 결과
부서별 인원 수
Map 생성.
38. mapping()
downstream에서 자주 사용.
39. 예시
Collectors.groupingBy(
User::getDepartment,
Collectors.mapping(
User::getName,
Collectors.toList()
)
)
40. 결과
부서별 이름 목록
생성.
41. collectingAndThen()
후처리 가능.
42. 예시
Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList
)
43. 의미
수집 후 immutable 변환
입니다.
44. Collector 내부 구조
실제로 Collector는 꽤 복잡.
핵심 구성:
| supplier | 결과 container 생성 |
| accumulator | 데이터 누적 |
| combiner | 병렬 결과 병합 |
| finisher | 최종 변환 |
45. 왜 combiner 필요할까?
병렬 Stream 때문.
46. parallelStream()
parallelStream()
에서는:
부분 결과 여러 개 생성
가능.
47. 그래서 combiner 등장
부분 결과 병합
수행.
48. mutable reduction
collect는 사실상:
mutable reduction
입니다.
즉:
가변 객체에 누적
하는 방식.
49. reduce와 차이
| reduce | immutable 누적 |
| collect | mutable 수집 |
50. 실무에서 많이 쓰는 패턴
대표:
DTO 그룹핑
groupingBy(User::getTeam)
통계 계산
averagingInt(...)
summingInt(...)
문자열 조합
joining(",")
51. 성능 주의점
groupingBy는:
Map 생성 비용
존재.
대용량 데이터 시 메모리 사용 증가 가능.
52. 병렬 Stream 주의점
Collector가:
thread-safe 보장 안 하면
병렬 처리 문제 가능.
53. groupingByConcurrent()
병렬 최적화용 존재.
Collectors.groupingByConcurrent(...)
54. 실무에서 자주 하는 실수
1) toMap 중복 key 미처리
IllegalStateException 발생.
2) groupingBy 남용
메모리 사용 증가 가능.
3) 병렬 Stream + mutable 객체 사용
동시성 문제 가능.
4) collect와 reduce 차이 이해 부족
mutable/immutable 차이 중요.
55. 핵심 흐름 요약
Stream
↓
Collector 전달
↓
데이터 누적(accumulate)
↓
필요 시 병합(combine)
↓
최종 결과 반환
56. 가장 중요한 핵심 한 줄
Collector는
“Stream 결과를 원하는 구조로 수집하는 전략 객체”
입니다.
57. 정리
Collector는 단순 List 변환 API가 아닙니다.
실제로는:
- Stream Pipeline
- mutable reduction
- grouping
- 병렬 수집
- downstream collector
전체와 연결되는 Stream 핵심 수집 메커니즘입니다.
특히 실무에서는:
- groupingBy
- toMap
- downstream collector
- collectingAndThen
- 병렬 collect 구조
를 정확히 이해하는 것이 매우 중요합니다.
다음 글에서는:
Optional<T> 사용법
을 NullPointerException 방지, map/flatMap/orElse 차이, Optional 남용 문제까지 포함해서 깊게 정리해보겠습니다.
'language > java' 카테고리의 다른 글
| Java Optional 남용 문제 완벽 이해하기 (0) | 2026.05.28 |
|---|---|
| Java Optional<T> 사용법 완벽 이해하기 (0) | 2026.05.28 |
| Java Method Reference(::) 완벽 이해하기 (0) | 2026.05.28 |
| Java Stream API 기초 완벽 이해하기 (0) | 2026.05.27 |
| Java 함수형 인터페이스(Function, Predicate, Consumer 등) 완벽 이해하기 (0) | 2026.05.27 |
댓글