안녕하세요 푸드테크팀 백엔드 개발자 박형민 입니다
이번 포스팅에서는 저번 Stream 소개 글에 이에 가이드글을 작성해보고자 합니다.
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
스트림은 중복된 요소를 제거하고 고유 요소로 이루어진 스트림을 반환하는 distinct 메소드도 지원합니다.
고유 여부는 스트림에서 만든 객체의 hashCode, equals 로 결정합니다.
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,123,41,5,1,2,3,4,5,5,6,7,8)
.stream()
.filter(number->number%2==0)
.distinct()
.collect(Collectors.toList());
자바 9 이상 부터는 takeWile 메소드와 dropWhile 메소드를 제공합니다.
takeWile 메소드는, predicate를 만족하지 않는 첫 번째 지점부터 마지막 스트림을 버립니다.
takeWhile 메소드는 조건에 맞지않는 그 순간 Stream 조회를 종료하기 때문에 정렬되어있는 Stream 에 매우 유용합니다.
// 전체 리스트 순회
List<Dish> filterMenu = specialMenu.stream()
.filter(dish -> dish.getCalories() < 320)
.collect(toList());
// 조건에 맞지 않으면 Stop
List<Dish> filterMenu = specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());
dropWhile메소드는, takeWhile 과 정반대의 결과를 추출합니다.
첫 번째 요소부터, predicate를 처음으로 만족하는 지점까지 버리고 나머지를 반환합니다.
dropWhile 은 프리디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버립니다.
프리디케이트가 거짓이되면, 그 즉시 작업을 중단하고 남은 모든 요소를 반환합니다.
// 처음으로 거짓이 되는 지점까지 버림.
List<Dish> filterMenu = specialMenu.stream()
.dropWhile(dish -> dish.getCalories() < 320)
.collect(toList());
limit(n) : 주어진 값 이하의 크기를 가지는 새로운 스트림을 반환하는 스트림 메소드입니다.
limit 은 조건에 맞는 요소가 채워지면 그 즉시 스트림을 반환합니다.
// 3개 요소 반환
List<Dish> filterMenu = specialMenu.stream()
.filter(dish -> dish.getCalories() < 320)
.limit(3)
.collect(toList());
// 처음 3개 요소 건너뛰기
List<Dish> filterMenu = specialMenu.stream()
.filter(dish -> dish.getCalories() < 320)
.skip(3)
.collect(toList());
// 요리명을 추출하는 예제
List<String> dishNames = menu.stream()
.map(Dish::getName)
.collect(toList());
// 단어 리스트의 글자수 추출
List<String> words = Arrays.asList("Modern", "Java", "In", "Action");
List<Integer> wordLengths = words.stream()
.map(String::length)
.collect(toList());
// map 을 연결하여 요리명의 글자수 추출
List<String> dishNames = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(toList());
Stream flatmap 예시
List<String> uniqueCharacters = words.stream()
.map(word -> word.split("")) // 각 단어를 개별 문자를 포함하는 배열로 변환
.flatMap(Arrays::stream) // 생성된 스트림을 하나의 스트림으로 평면화
.distinct()
.collect(toList());
boolean isMatch = menu.stream().allMatch(Dish -> dish.getCalories() < 1000)
boolean isMatch = menu.stream().anyMatch(Dish -> dish.getCalories() < 1000)
boolean isMatch = menu.stream().noneMatch(Dish -> dish.getCalories() < 1000)
// filter 와 findAny를 활용해 채식 요리를 선택하는 방법
Optional<Dish> dish = words.stream()
.filter(Dish::isVegetarian)
.findAny(); //findAny는 Optional 객체를 반환
// 3으로 나누어 떨어지는 첫 번째 제곱근 값을 반환하는 코드.
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> first = someNumbers.stream()
.map(n -> n * n)
.filter(n -> n % 3 == 0)
.findFirst();
//초깃값 0.
// 두 요소를 조합해 새로운 값을 만드는 BinaryOperator. 예제에서는 람다 표현식 (a, b) -> a + b를 사용했다.
//reduce로 다른 람다, 즉 (a, b) -> a * b를 넘겨주면 모든 요소에 곱셈을 적용할 수 있다.
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
Java 8 에서는 Integer 클래스에 두 숫자를 더하는 정적 sum 메서드를 지원하여 아래와 같이 사용할 수 있습니다.
int sum = numbers.stream().reduce(0, Integer::sum);
👏 초기값을 없앨수도 있습니다.
Optional sum = numbers.stream().reduce((a, b) -> a + b);
👏 Stream 최대 값, 최솟 값
Optional max = numbers.stream().reduce(Integer::max);
Optional min = numbers.stream().reduce(Integer::min);
ex) 객체로 변환하고 reduce를 사용해서 sum을 하는 과정
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum);
Stream에서는 기본형 특화 스트림을 제공해서 아래처럼 조금 더 명시적이고 간편하게 기본형 특화 메소드들을 사용할 수 있도록 합니다.
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
기본값이 없는 Stream 연산에서 최대 최솟값을 구할 떄, 이를 구별하기위해 기본형 특화 스트림 + Optional 기능을 제공합니다.
OptionalInt maxCalories = menu.stream()
.mapToInt(Dish::getCalories)
.max();
물론 Int 형 뿐만아니라 다른 기본형 특화 스트림 타입에도 적용이 가능합니다.
감사합니다!!
takeWile 메소드와 dropWhile 는 모르는 함수였는데!! 앞으로 요긴하게 쓸수 있을거 같습니다!