| 조건 | 권장 방식 | 이유 |
|---|---|---|
| 데이터 수가 적을 때 (<10,000) | for문 |
오버헤드 없음, 성능 우수 |
| 단순 누적/조건 카운트 | for문 |
명확하고 빠름 |
| 조건 필터링 + 매핑 + 집계 체이닝 | stream() |
가독성, 유지보수 유리 |
| 병렬 처리 필요 | parallelStream() |
CPU 바운드 작업에 효과적 |
| 조건 분기 많거나 디버깅 자주 | for문 |
흐름 제어가 쉬움 (break, continue 등) |
| 방식 | 처리량 (ops/ms) | 설명 |
|---|---|---|
for문 (단순 필터+합) |
~10,000 | 가장 빠름 |
stream() |
~7,000 | 람다/boxing 오버헤드 있음 |
parallelStream() |
> 20,000 (CPU 바운드 작업) | 멀티코어 환경에 유리 |
| 성능 역전 기준 | 약 10만 건 이상 | 데이터 많고 연산 복잡할수록 stream 우위 |
📌 작은 연산은 for문이 빠름. 대량 처리 or 체이닝은 stream이 유리.
| 항목 | for문 |
stream() |
|---|---|---|
| 성능 | 오버헤드 없음 | 람다/스트림 구조로 느릴 수 있음 |
| 제어 흐름 | break, continue 가능 |
불가능 (조건 조합으로 대응) |
| 디버깅 | IDE 친화적 | peek() 사용, 디버깅 불편 |
| side effect (로그 등) | 명시적 실행 | 지연 평가로 타이밍 예측 어려움 |
| 메모리 | 직접 관리 | map/collect 시 중간 객체 생성 |
| 병렬 처리 | 수동 구현 필요 | parallelStream() 제공됨 |
| 재사용성 | 낮음 | 파이프라인 분리, 조합 유리 |
| 항목 | 설명 |
|---|---|
| ✅ 조건 많은 필터링은 조건 통합 | filter(x -> cond1 && cond2)로 최소화 |
| ✅ 단일 연산은 for문, 다단계 연산은 stream | 처리 흐름에 따라 분리 |
| ✅ stream은 가독성 중심, for는 성능 중심 | 팀 코드 스타일에 맞춰 선택 |
| ✅ flatMap, groupingBy 등 복잡 처리 | stream이 유지보수 유리 |
| ⚠️ I/O, 부작용 연산은 stream 내 피할 것 | 예상 외 동작 발생 가능 (지연 평가) |
| ⚠️ parallelStream은 thread-safe 확인 필수 | 병렬 안전하지 않으면 오히려 문제 발생 |
| 패턴 목적 | 코드 예시 |
|---|---|
| 조건 필터링 | stream().filter(x -> x > 10) |
| 조건 + 매핑 | stream().filter(...).map(...) |
| 합계 계산 | stream().mapToInt(...).sum() |
| 첫 요소 찾기 | stream().filter(...).findFirst() |
| 키-값 매핑 | collect(Collectors.toMap(...)) |
| 분류 및 그룹화 | collect(Collectors.groupingBy(...)) |