필터링
filter 메서드
- boolean을 반환하는 함수를 인수로 받아서 일치하는 모든 요소를 포함하는 스트림 반환
distinct 메서드
- 고유 요소로 이루어진 스트림을 반환 (중복 제거)
스트림 슬라이싱
자바 9 는 스트림의 요소를 효과적으로 선택할 수 있도록 takeWhile, dropWhile 새로운 메서드 지원
takeWhile
- filter 와 달리 참이 아닐경우 거기서 멈춤 (filter는 참인 요소 모두 확인해서 가져옴)
dropWhile
- 거짓이 되는 지점까지 발견된 요소를 버린다. (takeWhile과 반대)
List<Dish> sliceMenu1 =
menu.stream()
.filter(dish -> dish.getCalories() < 320)
.collect(Collectors.toList());
List<Dish> sliceMenu2 =
menu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(Collectors.toList());
List<Dish> sliceMenu3 =
menu.stream()
.dropWhile(dish -> dish.getCalories() < 320)
.collect(Collectors.toList());
limit
- n 이하의 크기를 갖는 새로운 스트림 반환
List<Dish> sliceMenu =
menu.stream()
.filter(dish -> dish.getCalories() < 320)
.limit(3)
.collect(Collectors.toList());
skip
- 처음 n개 요소를 제외한 스트림 반환
List<Dish> sliceMenu =
menu.stream()
.filter(dish -> dish.getCalories() < 320)
.skip(2)
.collect(Collectors.toList());
매핑
map
- 인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑된다.
List<String> dishNames =
menu.stream()
.map(Dish::getName)
.collect(Collectors.toList());
flatMap
- 생성된 스트림을 하나의 스트림으로 평면화
// map 으로 전달한 람다는 각 단어의 String[](문자열 배열)을 반환한다는 점이 문제이다.
// map 메서드가 반환한 스트림의 형식은 Stream<String[]> 이다.
words.stream()
.map(word -> word.split(""))
.distinct()
.collect(Collectors.toList());
// Array.stream() 사용해서 해결하게 되면 별도의 스트림 리스트(List<Stream<String>>)이 만들어지면서 문제가 해결되지 않는다.
words.stream()
.map(word -> word.split(""))
.map(Arrays::stream)
.distinct()
.collect(Collectors.toList());
// flatMap 을 사용하면 해결가능
// flatMap은 각 배열을 스트림이 아니라 스트림의 콘텐츠로 매핑한다.
// 즉, 하나의 평면화된 스트림을 반환
words.stream()
.map(word -> word.split(""))
.map(Arrays::stream)
.distinct()
.collect(Collectors.toList());
검색과 매칭
anyMatch
- 적어도 한 요소와 일치하는지 확인
// menu에 채식 요리가 있는지 확인
if (menu.stream().anyMatch(Dish::isVegetarian)) {
System.out.println("The menu is (somewhat) vegetarian friendly");
}
allMatch
- 모든 요소와 일치하는지 확인
// 모든 요리가 1000 칼로리 이하면 건강식으로 간주
boolean isHealthy = menu.stream().allMatch(dish -> dish.getCalories() < 1000);
noneMatch
- 일치하는 요소가 없는지 확인 (allMatch와 반대)
// 위와 동일
boolean isHealthy = menu.stream().allMatch(dish -> dish.getCalories() >= 1000);
findAny
- 현재 스트림에서 임의의 요소 반환
// 임의의 채식 요리 선택
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findAny();
Optional<T> 클래스는 값의 존재나 부재 여부를 표현하는 컨테이너 클래스
null은 쉽게 에러를 일으킬 수 있으므로 자바 8에서 Optional<T>를 만들었다.
- isPresent() : Optional이 값을 포함하면 참, 포함하지 않으면 거짓 반환
- ifPresent(Consumer<T> block) : 값이 있으면 주어진 블록 실행
- T get() : 값이 존재하면 값을 반환, 값이 없으면 NoSuchElementException 일으킴
- T orElse() : 값이 있으면 값 반환, 없으면 기본값 반환
findFrist
- 첫번째 요소 반환
리듀싱
- 모든 스트림 요소를 처리해서 값으로 도출하는 연산
- '메뉴의 모든 칼로리의 합계를 구하시오.' '메뉴에서 칼로리가 가장 높은 요리는?' 와 같이 스트림 요소를 조합해서 더 복잡한 질의를 표현하는 연산
reduce
int sum = 0;
for (int x : numbers) {
sum += x;
}
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int product = numbers.stream().reduce(1, (a, b) -> a * b);
초깃값 없는 reduce
- Optional 객체 반환
Optional<Integer> product = numbers.stream().reduce((a, b) -> a * b);
- 최댓값, 최솟값 찾을수 있다.
Optional<Integer> max = numbers.stream().reduce(Integer::max);
count
- 스트림 요소 수를 세는 메서드
숫자형 스트림
기본형 특화 스트림
- IntStream
- DoubleStream
- LongStream
스트림을 기본형 특화 스트림으로 변환할 때
- mapToInt
- mapToDouble
- mapToLong
// 각 요리에서 칼로리 추출해서 더함
int calories= menu.stream()
.mapToInt(Dish::getCalories)
.sum();
기본형 특화 스트림을 스트림으로 변환
- mapToObj
예) 피타고라스를 만족하는 세 수
Stream<int[]> pythagoreanTriples =
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)})
);
rangeClosed : 주어진 범위의 수를 만듬
boxed : Intstream을 Stream<Integer>로 복원
flatMap : 생성된 각각의 스트림을 하나의 평준화된 스트림으로 만듬
pythagoreanTriples
.limit(5)
.forEach(t -> System.out.println(t[0] + " " + t[1] + " " + t[2]));
실행 결과
개선
기존에는 만족하는 수를 찾아서 넣어줬지만 개선한 코드는 a,b,c 세 수를 만든 다음에 우리가 원하는 조건으로 필터링
Stream<double[]> pythagoreanTriples2 =
IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)})
.filter(t -> t[2] % 1 == 1)
);
스트림 생성
Stream.of
- 값으로 스트림을 만듬
Stream<String> stream = Stream.of("Modern ", "Java ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
Stream.ofNullable
- null이 될 수 있는 객체를 스트림으로 만들 수 있다.
Stream<String> homeValueStream = Stream.ofNullable(System.getProperty("home"));
// System.getProperty 제공된 키에 대응하는 속성이 없으면 Null 반환 (home 에 대응하는 속성이 없어서 null)
Stream<String> values = Stream.of("config", "home", "user")
.flatMap(key -> Stream.ofNullable(System.getProperty(key)));
Arrays.stream
- 배열을 스트림으로 만듬
int[] numbers = {1,2,3,4,5};
int sum = Arrays.stream(numbers).sum(); // int 배열을 IntStream으로 변환
Stream.iterate, Stream.generate
- 함수에서 스트림을 만들 수 있는 정적 메서드
- 두 연산을 이용해서 무한 스트림, 즉 고정된 컬렉션에서 고정된 크기로 스트림을 만들었던 것과는 달리 크기가 고정되지 않은 스트림을 만들 수 있다.
iterate
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
generate
- iterate와 달리 연속적으로 계산하지 않고 Supplier<T>를 인수로 받아서 새로운 값을 생산한다.
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
'Java > [Java8] 모던인자바액션' 카테고리의 다른 글
스트림 (0) | 2022.02.15 |
---|---|
람다 표현식 (0) | 2022.02.11 |
동작 파라미터화 코드 전달 (0) | 2022.02.09 |