Java/기본

[Java] 스트림(Stream)

댕주 2024. 10. 27. 17:31

Java에서 스트림(stream)은 데이터 처리 작업을 보다 간결하고 효율적으로 수행하기 위한 API로, Java8에 추가되었다.

컬렉션(리스트, 집합 등)이나 배열 등의 데이터를 다룰 때, 필터링, 변환, 집계 등 다양한 작업을 선언형으로 할 수 있도록 돕는다.

스트림은 데이터를 반복적으로 처리하는 대신 파이프라인 방식으로 처리하는 것이 특징이다.

스트림을 간단히 말하면 데이터를 한 줄로 처리하는 작업 방식이라고 보면 된다.


특징

1. 선언형: for-loop와 같은 명령형 코드보다 간결하게 "무엇을 할지"에 집중

2. 파이프라인 처리: 여러 연산을 체인 형식으로 연결해 순차적으로 처리

3. 데이터 원본 불변성: 스트림 연산은 데이터 원본을 변경하지 않으며 새 스트림을 반환

4. 지연 연산(Lazy Evaluation): 중간 연산은 필요할 때만 실행되며, 모든 작업이 최종 연산이 호출될 때까지 실제로 수행되지 않음

 

구성 요소

1. 데이터 소스: 스트림은 컬렉션, 배열, 파일 등 데이터 원본에서 생성된다

2. 중간 연산: 스트림의 데이터를 변환하거나 필터링하는 작업. 이 연산들은 새로운 스트림을 반환하며, 최종 연산이 실행되기 전까지 지연된다

- filter, map, sorted, distinct 등

3. 최종 연산: 스트림에서 최종적으로 값을 반환하거나 결과를 얻는 연산. 이 연산이 호출될 때 중간 연산이 한 번에 수행된다

- collect, forEach, reduce, count 등

 

스트림이 제공하는 추상 개념 중 핵심

1. 데이터 원소의 시퀀스 (유한 또는 무한)

스트림은 데이터를 한 줄로 처리하기 때문에, 이 데이터가 유한한지 또는 무한한지가 중요하다.

유한 스트림: 리스트나 배열처럼 끝이 있는 데이터. [1, 2, 3]

무한 스트림: 끝이 없는 데이터. 예를 들어 계속 증가하는 숫자들 0, 1, 2, 3, ...

 

2. 스트림 파이프라인 (연속 작업하기)

스트림의 핵심은 데이터를 한 번에 한 단계씩 처리하면서 여러 작업을 연결할 수 있다는 점인데, 이 연결된 연속 작업을 파이프라인이라고 한다.

예를 들어 과일 이름이 있는 리스트가 있을 때, 이 리스트에서 이름이 5글자 이상인 과일만 골라서 대문자로 바꾸고, 최종적으로 리스트에 담아 출력해보자

List<String> fruits = List.of("apple", "banana", "cherry");

List<String> result = fruits.stream()
                            .filter(fruit -> fruit.length() > 5)
                            .map(String::toUpperCase)
                            .collect(Collectors.toList());
System.out.println(result); // [BANANA, CHERRY]

이렇게 한 줄씩 필터링하고, 변환하고, 최종적으로 리스트로 만들 수 있다. 스트림은 이런 연속된 작업을 간단하게 해준다.

 

장점

- 간결성: 선언적 방식으로 작성하여 코드가 간결하고 직관적

- 지연 연산: 필요할 때만 연산을 수행해 효율적

- 병렬 처리: .parallelStream() 을 사용해 간단히 병렬 처리가 가능