Stream
title: 2025-08-20 author: 강병호 date: 2025-08-20 category: TIL/강병호/2025/08 layout: post —
스트림에서 데이터의 처리 방법은 주로 스트림 API가 관리하기에 편안한 데이터 처리 기법을 제공한다. 이 말은 즉, 스트림 API 내부적으로 다한 최적화(코드의 병렬 실행 등)이 이루어 질 수 있다는 것이다. 이러한 것은 순차적인 반복을 단일 스레드로만 구현하는 외부 반복에서 처리할 수 없다.
해당 장에서는 이러한 스트림API가 지원하는 다양한 연산을 배울 것이며 다음과 같다.
- 필터링, 슬라이싱, 매칭
- 검색, 매칭, 리듀싱
- 특정 범위의 숫자와 같은 숫자 스트림 사용
- 다중 소스로부터 스트림 생성
- 무한 스트림
5.1 필터링
스트림의 요소를 선택하는 방법, 즉 프레디케이트로 필터링 방법과 고유 요소만 필터링하는 방법에 대해 알 필요가 있다.
프레디케이트로 필터링
Boolean
을 반환하는 프레디케이트를 인수로 받아서 이에 일치하는 모든 요소를 포함하는 스트림을 반환한다.
```
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
```
해당 코드에서 Dish::isVegetarian
이 프레디케이트로 filter
함수는 이를 인수로 받아서 필터링한다.
고유 요소 필터링
스트림에서 만든 객체의 hashCode
, equals
로 결정되는 고유 여부에 의해 판단된 고유 요소로 이루어진 스트림을 반환하는 것이다.
```
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.steram()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println)
```
해당 코드에서는 리스트의 모든 짝수를 선택 후 중복을 필터링하여 고유 오소만 남도록 한다.
5.2 스트림 슬라이싱
스트림의 요소를 선택, 스킵하는 방법을 의미한다.
프레디케이트를 이용한 슬라이싱
자바 9에서 스트림 요소를 효과적으로 선택하도록 takeWhile
, dropWhile
의 두 가지 메서드를 지원한다.
해당 메서드들의 효과를 설명하기 위한 데이터 소스는 다음과 같다.
List<Dish> specialMenu = Array.asList(
new Dish("seasonal fruit", true, 120, Dish.Type.OTHER),
new Dish("prawns", fasle, 300, Dish.Type.FISH),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries" true, 530, Dish.Type.OTHER)
);
TakeWhile
위 데이터 소스에서 320 칼로리 이하의 요리를 선택하기 위해 filter
를 사용한다고 가정하자.
```
List<Dish> filteredMenu = specialMenu.stream()
.filter(dish -> dish.getCaloreis() < 320)
.collect(toList());
```
filter
연산을 이용하면 전체 스트림을 반복하며 각 요소에 프레디케이트를 적용하여 처리하게 된다. 이 경우 리스트가 정렬되어 있다는 사실을 이용해 320칼로리보다 크거나 같은 요리가 나온 경우 반복 작업을 중단할 수 있다.(filter가 하지 못하는 작업)
그렇지만 여기서 아주 많은 요소가 큰 스트림에서는 연산의 속도에 큰 차이를 줄 수 있다.
이런 경우 takeWhile
연산을 이용할 수 있다.
```
List<Dish> slicedMenu1 = specialMenu.strema()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());
```
이를 이용해 무한 스트림을 포함한 모든 스트림에 프레디케이트를 적용해 스트림을 슬라이스 할 수 있다.
DropWhile
위 에시와 반대로 320칼로리보다 큰 요소를 탐색시 dropWhile
을 이용할 수 있따.
```
List<Dish> slicedMenu2 = specialMenu.stream()
.dropWhile(dish -. dish.getCaloreis() < 320)
.collect(toList());
```
dropWhile
은 takeWhile
과 정반대의 작업을 수행하는데 dropWhile
의 경우 프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버린다. 프레디케이트가 거짓이 되면 그 지점에서 작업을 중단하고 남은 모든 요소를 반환하게 된다.
스트림 축소
주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 것으로 limit
메서드를 지원한다.
```
List<Dish> dishes = specialMenu.stream()
.filter(dish -> dish.getCaloreis() > 300)
.limit(3)
.collect(toList());
```
해당 코드는 프레디케이트와 일치하는 처음 세 요소를 선택한 다음 즉시 결과를 반환하는 코드이다.
요소 건너뛰기
처음 n개 요소를 제외한 스트림을 반환하는 skip
메서드가 존재한다.
처음 n개를 가져오는limit
과 달리 n개 이후 스트림을 반환하기에 상호 보완적인 연산을 수행한다.
```
List<Dish> dishes = menu.stream()
.filter(d -> d.getCaloreis() > 300)
.skip(2)
.collect(toList());
```