Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

참새의 이야기

Chapter 5. 스트림 활용 본문

JAVA/모던 자바 인 액션

Chapter 5. 스트림 활용

참새짹짹! 2023. 11. 18. 13:52

필터링

stream의 filter 메서드는 인수로 받은 predicate와 일치하는 모든 요소를 포함하는 스트림을 반환한다.

List<Dish> vegetarianDished =menu.stream()
        .filter(Dish::isVegetarian)
        .collect(toList());

이 경우에는 Dish의 isVegetarian()이 true라면 모두 포함한 stream을 만들고 .collect(toList())가 리스트로 바꿔 반환한다.

distinct

아래와 같은 정수 리스트가 있다고 하자.

List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);

이 정수 리스트에서 짝수만을 출력하되, 같은 값에 대해서는 한 번만 출력하고 싶다면 distinct를 사용하면 된다.

같은 지에 대한 판단은 객체의 hashCode, equals로 한다.

takeWhile & dropWhile

List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 2, 9);

List<Integer> collect = numbers.stream()
        .takeWhile(integer -> integer < 6)
        .collect(toList());

위의 코드에서 collect 리스트는 [1, 3, 5]다.

4번 인덱스의 2도 6보다 작다는 조건에 맞지만 takeWhile은 하나라도 조건에 맞지 않는 요소가 발생하면 작업을 중단하고 다음 연산으로 넘어간다.

dropWhile은 takeWhile과 조금 다르게 작동한다.

takeWhile이 predicate가 처음으로 거짓이 되면 나머지를 버렸다면, dropWhile은 predicate가 처음으로 거짓이 되는 위치까지 발견한 것들을 버린다.

List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 2, 9);

List<Integer> collect = numbers.stream()
        .dropWhile(integer -> integer < 6)
        .collect(toList());

예를 들어 이런 경우에는 [1, 3, 5]까지를 버리고 [7, 2, 9]를 취한다.

limit

limit은 반환하는 스트림의 크기가 n이하가 되도록 한다.

n개가 되면 남은 요소를 검사하지 않고 바로 반환한다.

List<Dish> collect = menu.stream()
                                    .filter(dish -> dish.getCalories() > 300)
                                    .limit(3)
                                    .collect(toList());

위의 경우에 dish -> dish.getCalories() > 300에 breakPoint를 찍고 돌려보면 limit의 개수에 도달하자 남은 요소에 대해서는 dish -> dish.getCalories() > 300를 실행하지 않고 반환하는 것을 확인할 수 있다.

skip

skip을 사용하면 filter 조건에 맞는 두 요소를 n개 건너뛰고 나머지에 대해 로직을 실행한다.

매핑

스트림의 각 요소에 어떤 함수를 적용하고 싶다면 map을 사용하면 된다.

List<String> collect =menu.stream()
        .filter(dish -> dish.getCalories() > 300)
        .map(Dish::getName)
        .collect(toList());

위의 경우에는 필터링을 한 후에 map에서 Dish의 name을 getter로 반환한다.

그렇기 때문에 map 메서드의 반환은 String타입의 Stream이 된다.

평면화

flatMap은 일반 map과 달리 하나의 평면화된 스트림을 반환한다.

간단히 풀어 설명하자면, 각 요소를 다른 스트림으로 만든 다음에 하나의 스트림으로 연결하는 것이다.

검색과 매칭

  • allMatch
    • 모두 일치하는 지를 boolean으로 반환
  • anyMatch
    • 적어도 하나가 일치하는 지를 boolean으로 반환
  • noneMatch
    • 하나도 일치하지 않는 지를 boolean으로 반환
  • findFirst
    • 첫 요소를 반환
  • findAny
    • 임의의 한 요소를 반환

위의 5가지 메서드 중 allMatch, noneMatch, findFirst, findAny는 모든 스트림의 요소를 처리하지 않아도 결과를 알 수 있는 경우가 있다.

이런 경우 원하는 결과가 나오면 즉시 반환하는데 이를 쇼트서킷 평가라고 한다.

리듀싱

reduce를 이용해 반복 연산을 추상화할 수 있다.

int sum = numbers.stream()
                                    .reduce(0, Integer::Sum);

위의 예시처럼 reduce는 두 개의 인수를 갖는다.

첫째는 초깃값, 둘째는 반복할 연산이다.

초깃값 없이 연산만 가질 수도 있는데, 최댓값이나 최솟값을 찾을 때를 예시로 갖는다.

Optional<Integer> max = numbers.stream()
                                                                .reduce(Integer::max);

숫자형 스트림

Dish 클래스의 calories는 int로 선언되어 있다.

그렇다면, 위에서 소개한 reduce(Integer::sum) 은 int를 Integer로 박싱한 후 계산을 하게 된다.

Integer caloriesInteger =menu.stream()
        .map(Dish::getCalories)  //line 2
        .reduce(0, Integer::sum);

int caloriesInt =menu.stream()
        .mapToInt(Dish::getCalories) //line 6
        .sum();

이 계산을 효율적으로 처리하기 위한 기본형 특화 스트림을 소개한다.

mapToInt, mapToDouble, mapToLong과 같은 메서드를 사용하면 map과 같은 기능을 수행하지만, Stream 대신 특화된 스트림을 반환한다.

위의 코드에서도 line 2는 Stream를 반환하지만, line 6는 IntStream을 반환한다.

객체 스트림으로 복원

IntStream과 같은 숫자 스트림을 특화되지 않은 스트림으로 변환하려면 boxed()를 활용하면 된다.

범위

IntStream과 LongStream은 range, rangeClosed라는 두 가지 정적 메서드를 제공한다.

열린 구간과 닫힌 구간의 차이로, 해당 범위의 수로 구성된 Stream을 반환한다.

'JAVA > 모던 자바 인 액션' 카테고리의 다른 글

Chapter 4. 스트림 소개  (1) 2023.11.16
Chapter 3. 람다 표현식  (0) 2023.11.15
Chapter2. 동작 파라미터화  (2) 2023.11.14
Chapter 1. 자바의 변화  (0) 2023.11.14