본문 바로가기

Java

스트림 활용 정리

 

1. 필터링

1.1 프레디케이트로 필터링

filter 의 인수로 프레디케이트를 받는 방법이 있다.

 

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

 

1.2 고유 요소 필터링

 

스트림은 고유 요소르 이루어진 스트림을 반환하는 distinct 메서드도 지원한다.

 

List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream
        .filter(i -> i % 2 == 0)
        .distinct()
        .forEach(System.out::println);
 

 위 코드는 filter 를 통해 2, 2, 4 요소들이 필터링되고

distinct() 를통해 2, 4 만 전달이 된다.

결과적으로 2 와 4가 출력이 된다.

 

2. 슬라이싱

2.1 takewhile, dropwhile

칼로리가 낮은 순으로 음식들이 저장되어있는 리스트가 있다고 가정하자.

칼로리가 350 이하인 음식들을 추출하고 싶을 때 우리는 filter 를 사용할 수 있지만 takewhile 과 dropwhile 또한 사용할 수 있다.

(컬렉션이 정렬되어있음에 주의!)

 

List<Dish> sliceMenu = specialMenu.stream()
                                   .takeWhile(dish -> dish.getCalories() < 350)
                                    .collect(toList());

 

만약 칼로리가 350 보다 높은 음식들을 탐색하고 싶다면 다음과 같은 방법이 있다.

List<Dish> sliceMenu = specialMenu.stream()
                                    .dropWhile(dish -> dish.getCalories() < 350)
                                    .collect(toList());

 

2.2 limit

limit(n) 은 n 이하의 크기를 갖는 스트림을 반환한다.

 

2.3 skip

skip(n) 은 처음 n 개 요소를 제외한 스트림을 반환한다.

 

 

3. 매핑

3.1 map

map 에 전달되는 메서드를 수행하여 새로운 요소로 매핑하여 준다.

 

3.2 flatMap

예시로 flatMap 을 살펴보자.

예를들어 ["Hello", "World"] 리스트가 있고 결과로 ["H", "e", "l", "o", "W", "r", "d"] 를 반환하고 싶다.

아마 앞에서 보았던 distinct() 를 이용하여 중복된 문자를 필터링 하려고 했을 것이다. 즉 다음과 같다.

 

words.stream()
    .map(word -> word.split("")) <- Stream<String[]>
  .distinct() <- Steam<String[]>
  .collect(toList()); -List<String[]>

 

하지만 위 코드는 List<String[]> 형식의 결과물이 나온다.

의도했던 List<String> 과는 다른 값이다.

flatMap 을 이용하여 문제를 해결할 수 있다.

words.stream()
    .map(word -> word.split("")) <-Stream<String[]>
   .flatMap(Arrays::stream) <- Stream<String>
   .distinct() <- stream<String>
   .collect(toList()); <- List<String>

 

4. 검색과 매칭

4.1 anyMatch, allMatch, noneMatch

anyMatch 는 적어도 한 요소가 일치하는지

allMatch 는 모든 요소가 일치 하는지

noneMatch 는 모든 요소가 일치 하지 않는지 확인하여 불리언값을 반환한다.

 

이때 쇼크서킷 평가가 적용된다. (모든 요소를 다 계산하지 않아도 결과를 반환할 수 있다.)

 

4.2 findAny, findFirst

findAny 는 현재 스트림에서 임의의 요소를 반환한다.

findFirst 는 스트림의 첫번째 요소를 가지고 온다.

만약 요소의 반환 순서가 상관없다면 제약이 적은 findAny 를 사용하는 것이 좋다.

 

5. 리듀싱

5.1 reduce

reduce 연산은 스트림의 하나의 값이 될 때까지 람다에 정의한 연산을 수행한다.

List<Integer> numbers = Arrays.asList(2, 3, 4);
int product = numbers.steam().reduce(1, (a, b) -> a * b)
 

위의 코드 경우 초기값 1 과 첫번째 요소 2 를 람다로 전달하려 연산을 수행한다.

1 * 2 = 2

그 후 결과로 나온 2 와 다음 요소인 3 을 곱한다.

2 * 3 = 6

6 * 4= 24

즉 24 의 결과가 나혼다.

 

이때 초기값을 받지 않는 reduce 도 있다. 대신 반환값은 Optional 이다.

 

최댓값과 최솟값을 구할때도 reduce 를 사용할 수 있다.

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

 

6. 기본형 특화 스트림

기본형 특화 스트림?

IntStream, DoubleStream, LongStream 이 기본형 특화 스트림에 해당한다.

이러한 기본형 특화 스트림은 sum, max, min, average 등의 유틸리티 메소드를 지원한다.

 

기본형 특화 스트림 만들기 위해서는 mapToInt, mapToDouble, mapToLong 을 이용하면 되고,

기본형 특화 스트림을 다시 특화되지 않은 스트림으로 바꾸는 방법으로는 boxed() 가 있다.

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();

 

 

IntStream, LongStream 는 range 와 rangeClosed 메서드를 제공한다.

IntStream intStream = Intstream.rangeClosed(1, 100);

위의 코드는 1 부터 100 까지의 숫자 스트림을 만들어준다.

range : 시작 값과 종료 값이 결과에 포함되지 않는다.

rangeClosed : 시작 값과 종료 값이 결과 표함된다.

반응형

'Java' 카테고리의 다른 글

람다 표현식을 활용한 디자인패턴 - 템플릿 메서드  (0) 2020.04.08
람다 표현식을 활용한 디자인패턴 - 전략 패턴  (0) 2020.04.08
스트림 기본 정리  (0) 2020.04.04
Optional  (0) 2020.03.29
인터페이스, Interface  (0) 2020.02.17