자바 8부터 도입된 스트림(Stream)은 데이터를 물 흐르듯이 다룰 수 있게 하는 강력한 도구이다. 스트림을 이용하면 코드가 "어떻게(How)" 수행되는지보다, "무엇(What)"을 수행하고 싶은지에 집중할 수 있다. 이를 선언적 프로그래밍(Declarative Programming) 방식이라 한다.
스트림은 데이터의 흐름을 추상화한 것으로, 컬렉션이나 배열 등의 요소를 중간 연산과 최종 연산을 통해 순차적으로 처리하는 구조를 제공한다.
데이터 소스를 변경하지 않음(Immutable)
일회성(한 번만 소비 가능)
파이프라인(Pipeline) 구성
지연 연산(Lazy Operation)
병렬 처리(Parallel) 가능
List<String> names = List.of("Apple", "Banana", "Berry", "Tomato");
// "B"로 시작하는 이름만 필터링하고 대문자로 변환하여 리스트로 수집
List<String> result = names.stream()
.filter(name -> name.startsWith("B"))
.map(String::toUpperCase)
.toList();
result.forEach(System.out::println);
외부 반복: 개발자가 직접 루프를 돌려 처리한다.
for (String s : result) {
System.out.println(s);
}
내부 반복: 스트림 API가 자동으로 반복 처리한다.
names.stream()
.filter(name -> name.startsWith("B"))
.map(String::toUpperCase)
.forEach(System.out::println);
자바의 스트림 API는 지연 연산을 통해 최적화를 이루고 있다.
스트림은 파이프라인을 통해 데이터를 처리하며, 하나의 요소가 중간 연산을 통과하면 곧바로 다음 단계로 전달됩니다. 이를 통해 중간 데이터를 저장할 필요 없이 효율적으로 처리된다.
List<Integer> data = List.of(1, 2, 3, 4, 5, 6);
Integer result = data.stream()
.filter(i -> i % 2 == 0)
.map(i -> i * 10)
.findFirst()
.get();
System.out.println(result); // 출력: 20
위 코드에서 findFirst() 최종 연산은 첫 번째 조건 만족 시 바로 연산을 종료하여 불필요한 처리를 줄인다.
스트림 API를 잘 활용하면 데이터 처리 로직을 더욱 명료하게 표현하고, 효율적으로 구현할 수 있다. 이를 통해 유지보수가 쉬워지고 코드의 성능도 향상된다.