
1. Stream이란?
Java Stream은 컬렉션 데이터를 함수형 스타일로 처리할 수 있도록 도와주는 API이다. 기존의 반복문을 사용한 컬렉션 처리보다 간결하고 가독성이 높으며, 병렬 처리도 용이하다.
특징
- 선언형 스타일: 코드가 간결하고 가독성이 좋다.
- 중간 연산과 최종 연산: 연산을 구분하여 체이닝 가능
- 내부 반복 처리: for 문 없이 요소를 처리
- 병렬 처리 가능: parallelStream() 사용 시 병렬 실행 지원
2. Stream 생성 방법
Stream을 생성하는 방법은 여러 가지가 있으며, 주로 컬렉션이나 배열을 기반으로 생성한다.
2.1 컬렉션에서 생성
List<String> list = List.of("Apple", "Banana", "Cherry");
Stream<String> stream = list.stream();
2.2 배열에서 생성
String[] arr = {"A", "B", "C"};
Stream<String> stream = Arrays.stream(arr);
2.3 Stream 직접 생성
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
2.4 무한 스트림 (generate, iterate)
Stream<Double> randoms = Stream.generate(Math::random).limit(5);
Stream<Integer> numbers = Stream.iterate(1, n -> n + 2).limit(5);
3. Stream 연산 (중간 연산 & 최종 연산)
Stream은 **중간 연산(intermediate operation)**과 **최종 연산(terminal operation)**으로 구성된다.
3.1 중간 연산 (Intermediate Operations)
중간 연산은 스트림을 변환하는 연산이며, 최종 연산이 호출되기 전까지 실행되지 않는다 (Lazy Evaluation).
필터링 (filter)
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // 2, 4
매핑 (map)
List<String> words = List.of("java", "stream", "example");
words.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // JAVA, STREAM, EXAMPLE
정렬 (sorted)
List<Integer> nums = List.of(5, 3, 8, 1);
nums.stream()
.sorted()
.forEach(System.out::println); // 1, 3, 5, 8
중복 제거 (distinct)
List<Integer> nums = List.of(1, 2, 2, 3, 4, 4, 5);
nums.stream()
.distinct()
.forEach(System.out::println); // 1, 2, 3, 4, 5
제한 (limit) 및 건너뛰기 (skip)
Stream<Integer> infiniteStream = Stream.iterate(1, n -> n + 1);
infiniteStream.limit(5).forEach(System.out::println); // 1, 2, 3, 4, 5
3.2 최종 연산 (Terminal Operations)
최종 연산은 스트림의 요소를 소비하고 결과를 반환하며, 한 번 실행되면 스트림은 종료된다.
요소 출력 (forEach)
List<String> items = List.of("A", "B", "C");
items.stream().forEach(System.out::println);
개수 반환 (count)
long count = Stream.of(1, 2, 3, 4, 5).count();
System.out.println(count); // 5
요소 찾기 (findFirst, findAny)
Optional<Integer> firstEven = Stream.of(3, 5, 8, 9)
.filter(n -> n % 2 == 0)
.findFirst();
System.out.println(firstEven.get()); // 8
조건 검사 (allMatch, anyMatch, noneMatch)
boolean allEven = Stream.of(2, 4, 6).allMatch(n -> n % 2 == 0);
boolean anyEven = Stream.of(1, 3, 5, 6).anyMatch(n -> n % 2 == 0);
System.out.println(allEven); // true
System.out.println(anyEven); // true
요소 수집 (collect)
List<String> list = Stream.of("a", "b", "c")
.collect(Collectors.toList());
System.out.println(list); // [a, b, c]
최소 / 최대 값 (min, max)
Optional<Integer> min = Stream.of(3, 1, 4, 1, 5).min(Integer::compareTo);
System.out.println(min.get()); // 1
합계 및 평균 (reduce)
int sum = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
System.out.println(sum); // 10
4. 병렬 스트림 (Parallel Stream)
Stream은 기본적으로 **순차 스트림(Sequential Stream)**으로 동작하지만, 병렬 스트림을 사용하면 멀티코어 프로세서를 활용하여 성능을 향상시킬 수 있다.
4.1 병렬 스트림 생성
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
numbers.parallelStream()
.forEach(System.out::println); // 병렬로 실행됨
4.2 주의할 점
- 데이터 크기가 작다면 오히려 오버헤드로 인해 성능이 떨어질 수 있음
- 공유된 가변 상태를 변경하는 경우 동기화 문제가 발생할 수 있음
5. 정리
연산 | 설명 |
filter | 조건에 맞는 요소 필터링 |
map | 요소를 변환 |
sorted | 정렬 수행 |
distinct | 중복 제거 |
limit / skip | 요소 개수 제한 또는 건너뛰기 |
forEach | 모든 요소 처리 |
collect | 결과를 컬렉션으로 변환 |
reduce | 요소를 하나의 값으로 축소 |

Java Stream을 활용하면 가독성과 유지보수성을 높이면서도 강력한 데이터 처리 기능을 구현할 수 있다.

'Back_End > JAVA' 카테고리의 다른 글
얼리 리턴 패턴(Early Return Pattern) 이란? (0) | 2025.02.14 |
---|---|
Java의 Comparator vs Comparable (1) | 2025.02.14 |
싱글톤 패턴 (Singleton Pattern) (0) | 2025.02.13 |
자바의 람다식(Lambda Expression) (0) | 2025.02.12 |
POJO(Plain Old Java Object) 란? (1) | 2025.02.05 |