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());
```

dropWhiletakeWhile과 정반대의 작업을 수행하는데 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());
```

results matching ""

    No results matching ""