-
스트림 활용하기, 중간연산과 최종연산 #filter #map #findAny #reduceJAVA 2023. 3. 26. 15:53
스트림 활용하기, 중간연산과 최종연산
#filter #distinct
#takeWhile #dropWhile #skip #limit
#map #flatMap
#anyMatch #allMatch #noneMatch
#findAny #findFirst
안녕하세요? 장장스입니다.
오늘은 스트림 연산에 대해 정리해 보겠습니다.
1. 스트림 요소 필터링
filter 메서드
Stream<T> filter(Predicate<? super T> predicate);
fillter 메서드는 프레디케이트(Predicate)를 인수로 받아서 프레디케이트와 일치하는 모든 요소를 포함하는 스트림을 반환한다.
public static final List<Dish> menu = Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT), new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT), new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("rice", true, 350, Dish.Type.OTHER), new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("pizza", true, 550, Dish.Type.OTHER), new Dish("prawns", false, 400, Dish.Type.FISH), new Dish("salmon", false, 450, Dish.Type.FISH) );
위와 같이 menu 리스트가 있을 때,
List<Dish> vegetarianMenu = menu.stream() .filter(Dish::isVegetarian) .collect(toList()); vegetarianMenu.forEach(System.out::println);
isVegetarian 메서드는 Dish 인스턴스가 채소인지 확인하는 void->boolean 형 메서드이다.
출력 결과를 보면 다음과 같다.
french fries rice season fruit pizza
distinct 메서드
Stream<T> distinct();
distinct 메서드는 고유 요소를 필터링 하는 메서드이다.
고유 여부는 스트림에서 만든 객체의 hashCode, equals로 결정이 된다.
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
위와 같이 numbers 리스트가 있을때,
numbers.stream() .filter(i -> i % 2 == 0) .distinct() .forEach(System.out::println);
짝수를 필터링하여 distinct 메서드를 실행하면, 다음과 같이 중복된 숫자가 제거 되어 출력된다.
2 4
2. 스트림 슬라이싱
자바 9부터는 스트림의 요소를 선택할 수 있는 takeWhile, dropWhile 메서드를 지원한다.
List<Dish> specialMenu = Arrays.asList( new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("prawns", false, 300, Dish.Type.FISH), new Dish("prawns and chips", false, 320, 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) );
위와 같은 specialMenu 리스트가 있다.
takeWhile 메서드
takeWhile 메서드는 조건에 맞는 요소가 나왔을 때부터 반복 작업을 수행한다.
List<Dish> slicedMenu1 = specialMenu.stream() .takeWhile(dish -> dish.getCalories() < 320) .collect(toList()); slicedMenu1.forEach(System.out::println);
다음은 출력 결과이다.
season fruit prawns
dropWhile 메서드
dropWhile 메서드는 takeWhile 의 정반대로 조건에 맞는 요소가 나올 때부터 반복작업을 수행한다.
List<Dish> slicedMenu2 = specialMenu.stream() .dropWhile(dish -> dish.getCalories() < 320) .collect(toList()); slicedMenu2.forEach(System.out::println);
다음은 출력 결과이다.
prawns and chips rice chicken french fries
limit 메서드
주어진 값 이하의 크기를 갖는 새로운 스트림을 반환한다.
List<Dish> dishesLimit3 = menu.stream() .filter(d -> d.getCalories() > 300) .limit(3) .collect(toList()); dishesLimit3.forEach(System.out::println);
limit의 요소 3만큼 선택하여 리스트가 만들어진 것을 확인 할 수 있다.
pork beef chicken
skip 메서드
limit 메서드와 정반대로 처음 선택한 요소의 개수만큼을 제외한 스트림을 반환 할 수 있다.
List<Dish> dishesSkip2 = menu.stream() .filter(d -> d.getCalories() > 300) .skip(2) .collect(toList()); dishesSkip2.forEach(System.out::println);
처음 요소 2개를 제외한 모든 요소가 출력이 되는 것을 확인 할 수 있다.
chicken french fries rice pizza prawns salmon
3. 스트림 요소 매핑
map 메서드
스트림은 함수를 인수로 받는 map 메서드를 지원한다.
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑된다.
Function은 T->R 함수형 인터페이스!
List<String> words = Arrays.asList("Hello", "World", "Stream API", "map");
List<Integer> wordLengths = words.stream() .map(String::length) .collect(toList()); System.out.println(wordLengths);
map 메서드에 인자로 들어간 length 함수의 반환값이 int로 stream 요소의 값이 String에서 Integer로 매핑되는 것을 알 수 있다.
[5, 5, 10, 3]
flatMap
flatMap 메서드는 배열을 스트림이 아니라 스트림의 콘텐츠로 매핑한다. 하나의 평면화된 스트림을 반환한다.
List<String> words = Arrays.asList("Hello", "World", "Stream API", "map");
위 문자열 배열에서 중복을 제외한 알파벳을 뽑아보자.
words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .collect(toList());
flatMap 메서드는 문자열 배열(String[])을 하나의 평면화된 스트림으로 반환한다. 반환의 과정은 사진과 같다.
4.스트림 요소 매칭
anyMatch 메서드
프레디케이트로 적어도 한 요소와 일치하는지 확인하는 메서드이다.
menu.stream() .anyMatch(Dish::isVegetarian);
allMatch 메서드
스트림의 모든 요소가 주어진 프레디케이트와 일치하는지를 검사한다.
menu.stream() .allMatch(d -> d.getCalories() < 1000);
noneMatch 메서드
allMatch 메서드와 정반대 연산을 수행한다. 스트림의 모든 요소가 일치하는 요소가 없는지 확인한다.
menu.stream() .noneMatch(d -> d.getCalories() >= 1000);
5. 스트림 요소 검색
findAny 메서드
현재 스트림에서 임의의 요소를 반환한다. findAny 메서드를 다른 스트림연산과 연결해서 사용할 수 있다.
menu.stream() .filter(Dish::isVegetarian) .findAny();
findFirst 메서드
리스트 또는 정렬된 연속된 데이터로부터 생성된 스트트림에서 논리적인 아이템 순서가 정해져 있을 수 있다. 이런 스트림에서 첫 번째 요소를 찾아 내는 메서드이다.
menu.stream() .filter(Dish::isVegetarian) .findFirst();
6. 리듀싱 (reduce)
스트림에서는 스트림의 모든 요소를 처리해서 값으로 도출하는 리듀싱 연산을 지원한다.
reduce 메서드
reduce 연산은 초깃값과 두요소를 조합해서 새로운 값을 만드는 BinaryOperator<T>를 2개의 인수로 갖는다.
List<Integer> numbers = Arrays.asList(3, 4, 5, 1, 2);
int sum = numbers.stream().reduce(0, (a, b) -> a + b); System.out.println(sum);
위 예제에서는 BinaryOperator 대신 람다 표현식 (a, b) -> a+b 를 사용했다.
아래는 출력 결과이다.
15
reduce 연산은 스트림이 하나의 값이 될때까지 각 요소를 반복해서 조합한다.
초깃값이 없는 reduce 메서드
Optional<Integer> min = numbers.stream().reduce((a,b) -> a+b);
이처럼 초깃값을 설정하지 않는 reduce도 있다. 여기서 주의할 점은 Optional을 반환하는 것이다. 예를 들어, 스트림에 아무 요소가 없는 경우 값을 반환 할 수 없다. 때문에 Optional을 감싸 값을 반환한다.
reduce를 사용한 최댓값, 최솟값
reduce연산을 활용하여 최댓값과 최솟값을 연산 할 수 있다.
Optional<Integer> min = numbers.stream().reduce(Integer::min);
Optional<Integer> min = numbers.stream().reduce(Integer::max);
Post
References
- 모던 자바 인 액션
잘못된 코드나 내용이 있다면 댓글을 남겨주세요. 즉시 수정하도록 하겠습니다! :)
'JAVA' 카테고리의 다른 글
자바 스트림 설명부터 사용하는 이유 파헤쳐보기 #JAVA #스트림 (2) 2023.01.29 자바 람다 표현식 설명부터 사용법까지 완벽 정리 #JAVA #람다 (0) 2023.01.03 [객체 지향 설계] SOLID 원칙 (0) 2021.09.01 [JAVA] 자바 가비지 컬렉션 , Java Garbage Collection #GC (0) 2021.07.06 [JAVA] LinkedList를 접근 제어하는 ListIterator (0) 2021.01.24