스트림(Stream)은 자바 8부터 도입된 기능으로, 데이터의 흐름을 추상화하여 컬렉션이나 배열의 요소들을 선언형 방식으로 처리할 수 있게 해줍니다. 우리가 앞서 MyStreamV3를 구현하며 필터와 맵 등의 기능을 익힌 것처럼, 스트림 API는 데이터가 마치 물처럼 흐르듯 여러 연산을 거쳐 최종 결과를 만들어냅니다.
List<String> result = students.stream()
.filter(s -> s.getScore() >= 80)
.map(s -> s.getName())
.toList();
이처럼 무엇을 할지(What)에 집중하는 선언형 프로그래밍을 가능하게 합니다.
중간 연산(Intermediate Operation): filter, map 등. 데이터를 걸러내거나 변환합니다.
최종 연산(Terminal Operation): toList, forEach, findFirst 등. 실제 실행을 유발하며 스트림이 종료됩니다.
내부 반복(Internal Iteration): 루프를 명시하지 않고 스트림 내부에서 반복합니다.
메서드 참조(Method Reference): String::toUpperCase, System.out::println과 같이 람다식을 더 간결하게 표현합니다.
불변성(Immutable): 원본 데이터는 변경되지 않음
1회성(Consumed Once): 스트림은 한 번 사용하면 재사용 불가
지연 연산(Lazy Evaluation): 최종 연산이 실행되기 전까지 중간 연산은 실행되지 않음
파이프라인 구성(Pipelining): 연산들이 체이닝되어 요소 하나 단위로 흐름 처리됨
병렬 처리 지원: parallelStream()으로 병렬 연산 수행 가능
MyStreamV3: 일괄 처리 방식. 필터를 전체에 적용 후 결과 모아서 맵 수행.
Stream API: 파이프라인 처리 방식. 각 요소가 필터를 통과하면 바로 다음 연산으로 이어짐.
예시:
List<Integer> result = data.stream()
.filter(i -> i % 2 == 0)
.map(i -> i * 10)
.toList();
1 → X, 2 → 필터 통과 → map(2*10)처럼 하나의 요소가 파이프라인을 통과하듯 처리됨.
즉시 연산: MyStreamV3는 filter나 map 호출 시 바로 실행됨
지연 연산: Stream API는 toList(), forEach() 등의 최종 연산이 호출되기 전까지 실제 연산 수행 안함
data.stream()
.filter(...)
.map(...)
.findFirst().get(); // 이 순간에만 실행됨
→ 이런 방식 덕분에 단축 평가(Short-circuiting) 가능: findFirst는 조건을 만족하는 첫 값을 찾자마자 나머지 연산 생략
선언형 프로그래밍을 가능하게 함
불필요한 연산 줄이기 위한 지연 연산과 단축 평가 제공
스트림은 복잡한 데이터 처리 로직을 간결하게 만들고, 메모리 사용과 성능 면에서 효율적
MyStreamV3처럼 직접 구현한 방식과 비교하며 스트림 API의 장점을 체감할 수 있음