Contents
스트림 활용(필터링편)
   Sep 15, 2022     5 min read

Chapter5

스트림 활용 (필터링)

스트림 활용에서는 아래의 목록과 같이 다양항 것들이 있다. 이것들을 쪼개서 정리해서 포스팅 하겠다.

처음은 필터링(filter)에 대해서 한번 정리를 해보겠다.

항해를 시작해보겠다..

giphy-2


앞으로 배울 것들 목록

  • 필터링, 슬라이싱, 매칭
  • 검색, 매칭, 리듀싱
  • 특정 범위의 숫자와 같은 숫자 스트림 사용하기
  • 다중 소스로부터 스트림 만들기
  • 무한 스트림

  • 컬렉션 반복을 명시적으로 관리하는 외부 반복 코드
List<Dish> vegetarianDishes = new ArrayList<>();
for(Dish d : menu) {
	if(d.isVegetarian()){
  vegetarianDishes.add(d);
  }
}

위 코드를 내부적으로 처리하려면…

import static java.util.stream.Collectors.toList;
List<Dish> vegetarianDishes = menu.stream()
															    .filter(Dish::isVegetarian)
															    .collect(toList());

filter메서드에 필터링 연산을 인수로 넘겨줘보자. 처리 할 수 있다.

스트림API는 내부 반복 뿐 아니라 코드를 병렬로 실행할지 여부도 결정할 수 있다.

이러한 일은 순차적인 반복을 단일 스레드로 구현하는 외부 반복으로는 할 수 없다.

스트림API가 지원하는 연산을 이용해서 데이터 처리 질의

필터링

스트림의 요소를 선택하는 방법

  • 프레디케이트 필터링 방법
    • Predicate(Boolean을 반환하는 함수)를 인수로 받아서 Predicate와 일치하는 모든 요소를 포함하는 스트림을 반환한다.

        List<Dish> vegetarianMenu = menu.stream()
                                        .filter(Dish::isVegetarian) // <-- 채식 요리인지 확인하는 메서드 참조
                                        .collect(toList());
      
    • Predicate로 스트림 필터링

    Untitled

  • 고유 요소만 필터링하는 방법
    • 스트림은 고요 요소 이루어진 스트림을 반환하는 distinct 메서드도 지원한다.
    • 고유 여부는 스트림에서 만든 객체의 hashCode, equals로 결정된다.

    • 리스트의 모든 짝수를 선택하고 중복을 필터링한다.

        List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
        numbers.stream()
               .filter(i -> i % 2 == 0)
               .distinct()
               .forEach(System.out::println);
      
      
    • 스트림에서 고유 요소만 필터링

      Untitled 1

스트림 슬라이싱

프레디케이트를 이용한 슬라이싱

자바9에서 나온 스트림의 요소를 효과적으로 선택할 수 있도록 메서드를 지원한다.

  • takeWhile
  • dropWhile

  • takeWhile예제
List<Dish> specialMenu = Arrays.asList(
	new Dish("seasonal fruit", true, 120, Dish.Type.OTHER),
	new Dish("prawns", false, 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));

➡️320칼로리 이하의 요리를 선택

List<Dish> filterMenu = specialMenu.stream()
																	 .filter(dish -> dish.getCalories() < 320)
																	 .collect(toList()); // <-- seasonal fruit, prawns 목록

위 리스트는 이미 칼로리 순으로 정렬되어 있다는 사실에 생각해보자.

filter 연산을 이용하면 전체 스트림을 반복하면서 각 요소에 프레디케이트를 적용하게 된다. 따라서 리스트가 이미 정렬되어 있다는 사실을 이용해 320칼로리보다 크거나 같은 요리가 나왔을 때 반복 작업을 중단할 수 있다.

작은 리스트에서는 이와 같은 동작이 별거 아닌 것처럼 보일 수 있지만 아주 많은 요소를 포함하는 큰 스트림에서는 상당한 차이가 될 수 있다.

➡️이를 어떻게 지정할 수 있을까?

해결 : takeWhile연산

→ 무한 스트림을 포함한 모든 스트림에 프레디케이트를 적용해 스트림을 슬라이스할 수 있다.

List<Dish> slicedMenu1 = specialMenu.stream()
																		.takeWhile(dish -> dish.getCalories() < 320)
																	  .collect(toList()); // <-- Seasonal fruit, prawns 목록

  • dropWhile예제

➡️320 칼로리보다 큰 요소는 어떻게 탐색할까?

해결 : drowWhile 연산

List<Dish> slicedMenu2 = specialMenu.stream()
																		.dropWhile(dish -> dish.getCalories() < 320
																		.collect(toList()); //<-- rice, chicken, french fries 목록

➡️dropWhile은 takeWhile과 정반대의 작업을 수행한다.

→ dropWhile은 프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버린다.

→프레디 케이트가 거짓이 되면 그 지점에서 작업을 중단하고 남은 모든 요소를 반환한다.

→ dropWhile은 무한한 남은 요소를 가진 무한 스트림에서도 동작한다.

스트림 축소

스트림은 주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 limit(n) 메서드를 지원한다.

스트림이 정렬되어 있으면 최대 요소 n개를 반환할 수 있다.

➡️300 칼로리 이상의 세 요리를 선택해서 리스트를 만들 수 있다.

List<Dish> dishes = specialMenu.stream()
															 .filter(dish -> dish.getCalories() > 300)
															 .limit(3)
															 .collect(toList()); // <-- rice, chicken, french fries 목록

filter와 limit 조합 → 프레디케이트와 일치하는 처음 세 요소를 선택한 다음에 즉시 결과를 반환한다.

Untitled 2

정렬되지 않은 스트림(예를 들면 소스가 Set)에도 limit를 사용할 수 있다. 소스가 정렬되어 있지 않았다면 limit의 결과도 정렬되지 않은 상태로 반환된다.

요소 건너뛰기

  • 스트림은 처음 n개 요소를 제외한 스트림을 반환하는 skip(n) 메소드를 지원한다.
  • n개 이하의 요소를 포함하는 스트림에 skip(n)을 호출하면 빈 스트림이 반환된다.
  • limit(n)과 skip(n)은 상호 보완적인 연산을 수행한다.

➡️ 300칼로리 이상의 처음 두 요리를 건너뛴 다음에 300칼로리가 넘는 나머지 요리를 반환한다.

List<Dish> dishes = menu.stream()
												.filter(d -> d.getCalories() > 300)
												.skip(2)
												.collect(toList());

Untitled 3

퀴즈 - 필터링

  • 스트림을 이용해서 처음 등장하는 두 고기 요리를 필터링하시오.
List<Dish> dishes = menu.stream()
												.filter(d -> d.getTpye() == dish.Type.MEAT)
												.limit(2)
												.collect(toList());

필터링을 배우며….

이상으로 스트림 활용 (필터링 편)을 마치겠습니다.. 필터링으로 정말 많은 것을 할 수 있다고 생각했고 알고리즘에서 언젠가 써먹겠다는 나의 집념으로 여기까지 배웠다. 잘했다. 꾸준히 한 챕터씩 해보자.

giphy