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 |