
저자: 라울-게이브리얼 우르마 , 마리오 푸스코 , 앨런 마이크로프트
도서명: 모던 자바 인 액션
출판사: 한빛미디어
filter 메서드는 Predicate(불리언을 반환하는 함수)를 인수로 받아서 일치하는 모든 요소를 포함하는 스트림을 반환한다.
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
스트림은 고유 요소로 이루어진 스트림을 반환하는 distinct 메서드를 지원한다.
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
number.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);
Stream.of(1,2,3,4,5,6,7,8,9)
.filter(n -> n%2 == 0)
.forEach(System.out::println);
Stream.of(2,4,3,4,5,6,7,8,9)
.takeWhile(n -> n%2 == 0)
.forEach(System.out::println);
filter는 조건에 대해 다 검사하며 참인것만 다음으로 넘어가지만 takeWhile은 조건에 대해 참이 아닐경우 바로 거기서 멈추게 된다 즉 결과는 이런식으로 나오게 된다.
2
4
6
8
2
4
dropWhile은 프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버린다.
프레디케이트가 거짓이 되면 그 지점에서 작업을 중단하고 남은 모든 요소를 반환한다.
주어진 값 이하의 크기를 갖는 스트림을 반환한다.
List<Dish> dishes = specialMenu.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(toList()); //rice, chicken, french fries
처음 n개 요소를 제외한 스트림을 반환한다.
List<Dish> dishes = specialMenu.stream()
.filter(dish -> dish.getCalories() > 300)
.skip(2)
.collect(toList());
["Hello", "World"] 리스트가 있을때 ["H", "e", "l", "o", "W", "r", "d"] 고유문자로만 이루어진 리스트를 반환하려면 어떻게 해야할까?
word.stream()
.map(word -> word.split(""))
.disctinct()
.collect(toList());
위와같이 disctinct로 중복 문자를 필터링하기에는 map의 결과가 각 단어의 String[](문자열 배열)을 반환한다는 문제가 있다.
스트림은 파라미터로 제공되는 함수(Function<T, Stream>과 관련된 함수형 인터페이스)를 적용해서 스트림의 각 값을 다른 스트림으로 만든 다음에 모든 스트림을 하나의 스트림으로 연결하는 기능을 수행하는 flatMap이라는 메서드를 제공한다.

주어진 스트림에서 적어도 한 요소와 일치하는지 확인한다.
if (menu.stream.anyMatch(Dish::isVegetarian)) {
System.out.println("the menu is (somewhat) vegetarian friendly!!");
}
모든 요소가 일치하는지 확인한다.
boolean isHealthy = menu.stream().allMatch(dish -> dish.getCalories() < 1000);
일치하는 요소가 하나도 없는지 확인한다.
boolean isHealthy = menu.stream().noneMatch(dish -> dish.getCalories() >= 1000);
anyMatch, allMatch, noneMatch 메서드는 자바의 &&, ||과 같이 쇼트서킷 기법을 사용한다.
현재 스트림에서 임의의 요소를 반환한다.
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findAny();
Optional이란?
Optional 클래스는 값의 존재나 부재 여부를 표현하는 컨테이너 클래스이다.
위 예제에서 findAny는 아무 요소도 반환하지 않을 수 있기 때문에 null을 방지하고자 사용되었다.
Optional의 메소드
isPresent(): Optional이 값을 포함하면 true, 포함하지 않으면 false를 반환
isPresent(Consumer b lock) : 값이 있으면 주어진 블록을 실행
T get() : 값이 존재하면 반환, 없으면 NoSuchElementException을 발생
T orElse(T other) : 값이 있으면 반환, 없으면 기본값을 반환
스트림에서 첫 번째 요소를 찾을때 사용한다.
Optional<Integer> firstNumber = someNumbes.stream()
.map(n -> n * n)
.filter(n -> n % 3 == 0)
.findFirst();
for-each 루프를 이용해서 리스트의 숫자 요소를 더하는 코드
int sum = 0;
for ( int x : numbers ) {
sum += x;
}
reduce를 사용
int sum = numbers.stream().reduce(0, (a,b) -> a + b);
메서드 참조
int sum = numbers.stream().reduce(0, Integer::sum);
Optional 객체를 반환한다.
Optional<Integer> sum = numbers.stream().reduce(Integer::sum);
Optional<Integer> max = numbers.stream().reduce(Integer::max);
단계적 반복으로 합계를 구할때는 sum 변수를 공유해야 하므로 쉽게 병렬화가 어렵다.
하지만 reduce를 이용하면 내부 반복이 추상화되면서 내부 구현에서 병렬로 reduce를 실행할 수 있게 된다.
물론 병렬로 실행하기 위해서는 연산이 어떤 순서로 실행되더라도 결과가 바뀌지 않는 구조여야 한다.
스트림 연산은 각각 다양한 작업을 수행한다. 따라서 각각의 연산은 내부적인 상태를 고려해야한다.
map, filter 등은 입력 스트림에서 각 요소를 받아 0 또는 결과를 출력 스트림으로 보낸다.
따라서 이들은 보통 상태가 없는, 즉 내부 상태를 갖지 않는 연산(stateless operation)이다.
reduce, sum, max 같은 연산은 결과를 누적할 내부 상태가 필요하다. 하지만 내부 상태는 int, double 등과 같이 작은 값이며, 스트림에서 처리하는 요소 수와 관계없이 한정(bounded)되어있다.
반면 sorted나 distinct 같은 연산을 수행하기 위해서는 과거의 이력을 알고있어야 한다. 예를 들어 어떤요소를 출력스트림으로 추가하려면 모든 요소가 버퍼에 추가되어 있어야 한다. 따라서 데이터 스트림의 크기가 크거나 무한이라면 문제가 생길 수 있다. 이러한 연산을 내부 상태를 갖는 연산(stateful operation)이라 한다.
https://vesselsdiary.tistory.com/156
https://dev-kani.tistory.com/33
https://highlighter9.tistory.com/43