JAVA
JAVA - 스트림(Stream)
윤승
2025. 3. 13. 20:48
✏️ 자바 스트림(Stream)이란?
스트림(Stream)은 데이터를 효율적으로 처리할 수 있는 흐름이며, 기존의 for 문이나 Iterator보다 가독성과 재사용성이 뛰어난 선언형 스타일로 작성할 수 있다.
✏️ 스트림의 특징
- 선언형 스타일
- for 문이나 Iterator를 사용하지 않고, 데이터를 변환하고 필터링하는 작업을 간결하게 표현할 수 있다.
- 일관된 방식으로 데이터 처리 가능
- List, Set, Map, 배열 등 다양한 데이터 소스를 같은 방식으로 다룰 수 있다.
- 데이터 흐름 방식
- 데이터 준비 → 중간 연산 → 최종 연산 순으로 처리된다.
✏️ for 문 vs 스트림 비교
각 요소를 10배로 변환 후 출력하는 예시로 알아보자
- arrayList 의 각 요소를 10배로 변환한다.
- 아래 예시를 보고 for 문과 스트림 을 비교해보자
▼ for 문 (명령형 스타일)
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// ArrayList 선언
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// for 문을 사용한 방식
List<Integer> ret1 = new ArrayList<>();
for (Integer num : arrayList) {
int multipliedNum = num * 10; // 각 요소 * 10
ret1.add(multipliedNum);
}
System.out.println("ret1 = " + ret1); // [10, 20, 30, 40, 50]
}
}
특징:
- 명령형(Imperative) 스타일: 어떻게 동작하는지를 한 단계씩 설명해야 함.
- 가독성↓: for 문을 사용하면 코드 길이가 길어짐.
- 명확한 데이터 변환 과정: num * 10 후 ret1.add() 수행.
▼ 스트림 (선언형 스타일)
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// ArrayList 선언
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// 스트림을 활용한 방식
List<Integer> ret2 = arrayList.stream()
.map(num -> num * 10) // 각 요소 * 10
.collect(Collectors.toList());
System.out.println("ret2 = " + ret2); // [10, 20, 30, 40, 50]
}
}
특징:
- 선언형(Declarative) 스타일: 무엇을 할 것인지만 명확히 기술.
- 가독성↑: 한 줄로 데이터 변환을 표현할 수 있어 간결함.
- 병렬 처리 가능: .parallelStream()을 사용하면 멀티스레드로 처리 가능.
✏️ 스트림을 사용하여 각 요소를 10배로 변환하는 과정
스트림 처리 순서
1️⃣ stream() → 2️⃣ map() → 3️⃣ collect() 순으로 데이터 흐름을 처리합니다.
1. stream(): 데이터 준비
- 컬렉션(List, Set 등)을 스트림 형태로 변환하여 데이터를 처리할 준비를 합니다.
- 스트림은 요소를 하나씩 처리하며, 다양한 연산을 수행할 수 있습니다.
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Stream<Integer> stream = arrayList.stream();
2. map(): 중간 연산 (데이터 변환)
- map()은 각 요소를 주어진 함수에 적용하여 새로운 값을 생성합니다.
- 여기서는 각 요소를 10배로 변환하는 연산을 수행합니다.
Stream<Integer> mappedStream = arrayList.stream().map(num -> num * 10);
3. collect(): 최종 연산 (결과 수집)
- collect()는 스트림에서 처리된 데이터를 List, Set 등 원하는 형태로 변환합니다.
- 최종 연산이 실행되면 스트림은 더 이상 사용할 수 없습니다.
List<Integer> result = arrayList.stream()
.map(num -> num * 10)
.collect(Collectors.toList());
System.out.println(result); // [10, 20, 30, 40, 50]
전체 코드 예제
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// ✅ 1. 데이터 준비
List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
// ✅ 2. 중간 연산 (각 요소를 10배로 변환)
// ✅ 3. 최종 연산 (List로 수집)
List<Integer> result = arrayList.stream()
.map(num -> num * 10)
.collect(Collectors.toList());
System.out.println(result); // [10, 20, 30, 40, 50]
}
}
✏️ 스트림의 장점
✔️ 반복문 없이 간결한 코드
✔️ 가독성이 높아 유지보수가 쉬움
✔️ 데이터 소스에 관계없이 동일한 방식으로 처리 가능
✔️ 병렬 처리를 쉽게 구현 가능 (parallelStream())