목차
필터링
Predicate 필터링
filter는 프레디케이트(boolean을 반환하는 함수)를 인수로 받아서 true로 반환되는 요소를 모은 스트림을 반환한다
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
Distict 필터링
distinct는 객체를 hashCode, equals로 비교하여 고유한 요소를 모은 스트림을 반환한다
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);
슬라이싱
칼로리 순으로 정렬된 메뉴 리스트에서 320 칼로리 이하의 요소를 선택하려면 어떻게해야할까??
filter를 사용할 수 있다. filter는 스트림의 모든 요소에 프레디케이트를 적용하는데,
리스트가 이미 정렬된 상태에서 320 칼로리 초과가 나오면 그 이후로 프레디케이트가 적용되는 의미가 있을까?? 없다.
takeWhile은 정렬된 스트림에서 false가 나오면 반복을 멈추고 요소의 시작~멈춘 시점까지 반환한다.
takeWhile은 정렬된 스트림에서 320칼로리 이하를 모으고, 320칼로리 초과인 메뉴가 나왔을 때 반복작업을 중단한다.
List<Dish> slicedMenu1 = menu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());
dropWhile은 정렬된 스트림에서 false가 나오면 반복을 멈추고 멈춘시점~요소의 끝까지 반환한다.
dropWhile은 정렬된 스트림에서 320칼로리 이하를 버리고, 320칼로리 초과인 메뉴가 나왔을 때 반복작업을 중단한다.
List<Dish> slicedMenu1 = menu.stream()
.dropWhile(dish -> dish.getCalories() < 320)
.collect(toList());
Limit 축소
주어진 값 이하의 크기를 갖는 스트림을 반환한다.
limit(n)이면 최대 n개를 반환할 수 있다.
List<Dish> dishes = menu.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(toList());
----------------------------------------
최대 3개가 반환된다.
skip 건너뛰기
처음 n개를 제외한 스트림을 반환한다.
List<Dish> dishes = menu.stream()
.filter(dish -> dish.getCalories() > 300)
.skip(2)
.collect(toList());
-------------------------------------
처음에서 2개를 건너뛴 스트림을 반환한다
Mapping 맵핑
각 요소에 함수를 적용하는 map
스트림은 함수를 인수로 받는 map을 지원한다.
함수는 각 요소에 적용되어 새로운 요소로 맵핑된다.
(Dish객체의 Stream에 Dish::getName함수를 적용하여 String의 List를 반환한다)
map은 map끼리 연결할 수 있다.
List<String> dishNames = menu.stream() //Dish객체의 Stream
.map(Dish::getName) //각 메뉴의 이름을 반환한다
.collect(toList());
---------------------------------------
List<Integer> dishNames = menu.stream() //Dish객체의 Stream
.map(Dish::getName) //각 메뉴의 이름을 반환한다
.map(String::length) //메뉴 이름의 길이를 반환한다
.collect(toList());
스트림 평면화 flatMap
["Hello", "World"] 리스트에서 고유 문자로 이루어진 ["H", "e", "l", "o", "W", "r", "d"] 를 반환하려면 어떻게 해야할까?
map을 이용해서 문자를 나누고, distinct로 중복을 제거하면될까?
결과적으로, 이 방법은 실패하게된다.
words.stream()
.map(s -> s.split("")) //단어를 개별 문자의 배열로 반환
.distinct()
.collect(toList());
---------------------------------------
map
s = "Hello" 일때 : ["H", "e", "l", "l", "o"]
s = "World" 일때 : ["W", "o", "r", "l", "d"]
distinct
["H", "e", "l", "l", "o"] 묶음과 ["W", "o", "r", "l", "d"] 묶음 자체 비교 -> 중복된 묶음 아님
flatMap은 각 배열의 값을 단일 원소 스트림으로 반환할 수 있다
words.stream()
.map(s -> s.split("")) //단어를 개별 문자의 배열로 반환
.flatMap(Arrays::stream) //배열의 요소를 개별 스트림으로 반환
.distinct()
.collect(toList());
---------------------------------------
map
s = "Hello" 일때 : ["H", "e", "l", "l", "o"]
s = "World" 일때 : ["W", "o", "r", "l", "d"]
flatMap
Arrays::stream은 배열을 스트림으로 반환해준다.
반환값 : ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"]
distinct
["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"] 묶음에서 중복제거
일치 검사 any / all / noneMatch
적어도 한 요소와 일치하는지 확인 anyMatch
하나라도 채식요리이면 true가 반환된다.
boolean vegetarian = menu.stream().anyMatch(Dish::isVegetarian);
모든 요소와 일치하는지 확인 allMatch
모든 요리가 채식요리여야 true가 반환된다.
boolean vegetarian = menu.stream().allMatch(Dish::isVegetarian);
모든 요소와 일치하지 않는지 확인 noneMatch
모든 요리가 채식요리이지 않아야 true가 반환된다.
boolean vegetarian = menu.stream().noneMatch(Dish::isVegetarian);
요소 검색 findAny / findFirst
일치하는 임의의 요소 반환 findAny
병렬스트림에서는 첫번째 요소를 찾기 어렵다.
요소의 반환순서가 상관없다면 findAny를 사용하자.
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findAny();
일치하는 첫번째 요소 반환 findFirst
병렬 스트림에서는 첫번째 요소를 찾기 어렵다.
정렬된 스트림에서 findFirst를 사용하자.
Optional<Dish> dish = menu.stream()
.sorted(Comparator.comparing(Dish::getCalories))
.filter(Dish::isVegetarian)
.findFirst();
리듀싱
스트림의 모든 요소를 반복해서 처리하고, 하나의 값으로 도출하는 것을 리듀싱 연산이라고 한다.
int sum = 0;
for(int x : numbers){
sum = sum + x;
}
위 코드를 reduce를 이용해 표현하면 아래와 같다
초기값은 0으로 시작하고, numbers의 값을 하나씩 꺼내 더한다
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int sum = numbers.stream().reduce(0, Integer::sum);
reduce로 합계를 구하는것과, 기존 외부반복의 합계를 구하는 것에는 어떤 차이가 있을까?
외부반복을 이용하면 sum을 공유해야하므로 쉽게 병렬화하기 어렵지만
reduce를 이용하면 내부반복이 추상화되면서 내부구현에서 병렬로 reduce를 실행할 수 있게된다
기본형 특화 스트림
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum)
위 코드에는 Integer를 int로 변환하는 박싱 비용이 숨어있다.
스트림은 숫자 스트림을 효율적으로 처리할 수 있도록 IntStream, DoubleStream, LongStream을 제공한다.
기본형 특화 스트림은 오직 박싱 과정에서 일어나는 효율성과 관련있으며,
스트림에 추가기능을 제공하지 않는다.
일반 스트림 -> 특화 스트림
스트림을 특화 스트림으로 변환할때는 mapToInt, mapToDouble, mapToLong을 가장 많이 사용한다.
int calories = menu.stream()
.mapToInt(Dish::getCalories) //IntStream 반환
.sum();
특화 스트림 -> 일반 스트림
특화스트림을 다시 객체 스트림으로 변환하고자 할때는 boxed메서드를 사용한다.
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
다양한 스트림 만들기
정적인 스트림 만들기 Stream.of
Stream<String> stream = Stream.of("Modern", "Java", "In", "Action");
빈 스트림 만들기 Stream.empty()
Stream<String> emptyStream = Stream.empty();
Null일 수 있는 스트림 만들기 Stream.ofNullable()
Stream<String> valueStream = Stream.ofNullable(System.getProperty("home"));
배열로 스트림 만들기 Arrays.stream()
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
무한 스트림
크기가 고정되지 않은 스트림을 만들 수 있다.
보통 무한한 값을 출력하지 않도록 limit와 함께 사용한다.
무한 스트림 만들기 - iterate
초기값 0, 이전결과에 2씩 더하며 무한스트림을 생성하는 코드이다.
Stream
.iterate(0, n -> n+2)
.limit(10)
.forEach(System.out::println);
피보나치 수열 집합을 만드는 코드이다.
(0, 1), (1, 1), (1, 2), (2, 3), (3, 5), (5, 8)....
Stream
.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0]+t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out::println); //0, 1, 1, 2, 3, 5, 8, ...
무한 스트림 만들기 - generate
iterate와 달리 generate는 생산된 값을 연속적으로 계산하지 않고, Supplier<T>를 인수로 받아 새로운 값을 생산한다.
Stream
.generate(Math::random)
.limit(5)
.forEach(System.out::println);
#모던액션인자바 #자바 #자바8 #자바스트림 #스트림 #스트림활용 #필터링 #슬라이싱 #요소검색 #스트림필터링 #스트림슬라이싱 #스트림맵핑 #스트림평면화 #스트림일치확인 #스트림리듀싱 #기본형특화스트림 #정적스트림 #빈스트림 #무한스트림
'Backend' 카테고리의 다른 글
[SpringBoot] Apache Poi를 이용한 엑셀 다운로드 구현 (0) | 2022.08.20 |
---|---|
[Spring Boot] FeignClient와 ExceptionHandler | FeignClient의 응답값 그대로 반환하기 (1) | 2022.07.29 |
모던 자바 인 액션 - Stream(스트림)이란?, 스트림특징, 내부반복/외부반복, 게으른중간연산 (0) | 2022.07.11 |
모던 자바 인 액션 - 람다표현식, 함수형인터페이스 (1) | 2022.07.10 |
모던 자바 인 액션 - 람다 탄생 과정 (0) | 2022.05.06 |