filter
메서드
distinct
메서드
List<Integers> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);
스트림의 요소를 효과적으로 선택할 수 있도록 takeWhile
, dropWhile
지원함
이미 정렬된 리스트에서는 필터링보다는 takeWhile
함수를 쓰는 것이 효율적임
List<Dish> slicedMenu = specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());
takeWhile
과 정반대의 작업 수행limit(n)
메서드: 최대 요소 n개 반환
skip(n)
: n개의 요소를 건너뜀
map
List<String> dishnames = menu.stream()
.map(Dish::getName)
.collect(toList())
flatMap
메서드: 하나의 평면화된 스트림 반환
List<String> uniqueCharacters =
words.stream()
.map(word -> word.split("")) // 각 단어를 개별 문자를 포함하는 배열로 반환
.flatMap(Arrays::stream) // 생성된 스트림을 하나의 스트림으로 평면화
.distinct()
.collect(toList());
anyMatch
: predicate이 주어진 스트림에서 적어도 한 요소와 일치하는지 확인
if (menu.stream().anyMatch(Dish::isVegan)) {
System.out.println("The menu is vegan friendly");
}
allMatch
: predicate이 스트림의 모든 요소와 일치하는지
boolean isHealthy = menu.stream()
.allMatch(dish -> dish.getCalories() < 1000);
noneMatch
: 주어진 predicate와 일치하는 요소가 없는지 확인
allMatch
와 반대 연산boolean isHealthy = menu.stream()
.noneMatch(d -> d.getCalories() >= 1000);
anyMatch
, allMatch
, noneMatch
는 스트림 쇼트서킷 기법을 사용한다
&&
, ||
와 같은 연산limit
또한 쇼트서킷findAny
: 현재 스트림에서 임의의 요소를 반환
filter
와 함께 쓰이면 유용Optional<Dish> dish = menu.stream()
.filter(Dish::isVegan)
.findAny();
Optional: 값의 존재/부재 여부를 표현하는 컨테이너 클래스
findAny
는 아무 요소도 반환하지 않을 수 있는데 null
은 에러가 일어나기 쉬우므로 Optional
사용isPresent()
: Optional
이 값을 포함하면 true
Optional
이 값을 포함하지 않으면 false
ifPresent(Consumer<T> block)
: 값이 있으면 주어진 블록 실행T get()
: NoSuchElementException
일으킴T orElse(T other)
findFirst
vs. findAny
findAny
사용Optional<Dish> dish = menu.stream()
.filter(Dish::isVegan)
.findFirst();
리듀싱 연산: 모든 스트림 요소를 처리해서 값으로 도출하기
reduce
를 실행할 수 있게 됨sum
변수를 공유해야하므로 병렬화가 어려움reduce
는 parallelStream()
사용하면 됨초기값은 0인 상태에서 요소의 합
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
메서드 참조로 더 간단히 하면
int sum = numbers.stream().reduce(0, Integer::sum);
초기값은 1인 상태에서 요소의 곱
int product = numbers.stream().reduce(1, (a, b) -> a * b);
초기값 없는 reduce는 Optional을 반환함
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b);
reduce
연산은 새로운 값을 이용해 스트림의 모든 요소를 소비할 때까지 람다를 반복 수행하면서 최댓(최솟)값을 생산함
Optional<Integer> max = numbers.stream().reduce(Integer::max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);
transactions.stream()
.filter(t -> t.getYear == 2011)
.sorted(comparing(Transaction::getValue))
.collect(toList());
transactions.stream()
.map(t -> t.getTrader().getCity())
.distinct()
.collect(toList());
transactions.stream()
.map(t -> t.getTrader())
.filter(t -> t.getCity().equals("Cambridge"))
.sorted(comparing(Trader::getName))
.collect(toSet());
transactions.stream()
.map(t -> t.getTrader().getName())
.distinct()
.sorted()
.collect(joining());
joining
: 내부적으로 StringBuilder
를 이용해 모든 문자열을 반복적으로 연결해 새로운 문자열 객체를 만듬transactions.stream()
.filter(t -> t.getTrader().getCity().equals("Milan")
.findAny();
transactions.stream()
.filter(t -> t.getTrader().getCity.equals("Cambridge")
.map(Transaction::getValue)
.distinct()
.forEach(System.out::println);
transactions.stream()
.map(Transaction::getValue)
.reduce(Integer::max);
transactions.stream()
.min(comparing(Transaction::getValue));
참고: Modern Java in Action (라울-게이브리얼 등 지음)