Java함수형과 현대 Java

Stream 기본

Java Stream이 컬렉션과 어떻게 다르고, pipeline, intermediate, terminal operation을 어떻게 읽어야 하는지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

java
List<String> result = names.stream()
        .filter(name -> name.length() >= 3)
        .map(String::toUpperCase)
        .toList();

설명

  • Stream은 데이터를 저장하는 자료구조가 아니라, 데이터를 흘려 보내며 연산을 연결하는 pipeline 모델입니다. 이 점이 컬렉션과 가장 큰 차이입니다.
  • filter, map, sorted 같은 intermediate operation은 새 stream을 만들고, toList, count, forEach 같은 terminal operation이 실제 실행을 끝맺습니다.
  • Stream의 핵심 성질 중 하나는 지연(lazy) 평가입니다. terminal operation이 오기 전까지는 대부분의 intermediate 단계가 실제로 계산되지 않습니다.
  • 이 모델 덕분에 "무엇을 할 것인가"를 선언적으로 표현하기 쉬워집니다. 하지만 side-effect가 많은 코드나 디버깅이 복잡한 흐름에서는 오히려 불편할 수도 있습니다.
  • 좋은 Stream 코드는 loop를 억지로 치환한 코드가 아니라, 필터링-변환-집계가 자연스럽게 읽히는 코드입니다.

빠른 정리

개념의미
stream저장소가 아니라 연산 파이프라인
intermediate op새 stream을 만드는 중간 단계
terminal op실제 실행과 결과 생산 단계
장점선언적 데이터 처리
주의점side-effect가 많으면 오히려 읽기 어려움

주의할 점

Stream은 간결하지만 모든 loop를 대체하는 만능 문법은 아닙니다. 부수효과가 많고 단계가 복잡한 경우에는 전통적인 반복문이 더 명확할 수도 있습니다.

참고 링크

2 sources