티스토리 뷰
5.1 필터링
5.1.1 프레디케이트로 필터링
- 스트림 인터페이스는 filter 메서드를 지원함. filter 메서드는 프레디케이트를 인수로 받아서 프레디케이트와 일치하는 모든 요소를 포함하는 스트림을 반환함.
// 프레디케이트 필터링
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(Collectors.toList());
5.1.2 고유 요소 필터링
- 스트림은 고유 요소로 이루어진 스트림을 반환하는 distinct 메서드도 지원함.
// 고유 요소 필터링
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
5.2 스트림 슬라이싱
5.2.1 프레디케이트를 이용한 슬라이싱
- 자바 9은 스트림의 요소를 효과적으로 선택할 수 있도록 takeWhile, dropWhile 두 가지 새로운 메서드를 지원함.
- takeWhile을 이용하면 무한 스트림을 포함한 모든 스트림에 프레디케이트를 적용해 스트림을 슬라이스 할 수 있음.
- dropWhile은 프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버림.
List<Dish> specialMenu = Arrays.asList(
new Dish("seasonal fruit", true, 120, Type.OTHER),
new Dish("prawns", false, 300, Type.FISH),
new Dish("rice", true, 350, Type.OTHER),
new Dish("chicken", false, 400, Type.MEAT),
new Dish("french fries", true, 530, Type.OTHER)
);
// 320 초과한 값이 나오면 stop
List<Dish> slicedMenu1 = specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(Collectors.toList());
// 320 이하는 다 버림
List<Dish> slicedMenu2 = specialMenu.stream()
.dropWhile(dish -> dish.getCalories() < 320)
.collect(Collectors.toList());
5.2.2 스트림 축소
- 스트림은 주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 limit(n) 메서드를 지원함.
List<Dish> dishes1 = specialMenu.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(Collectors.toList());
5.2.3 요소 건너뛰기
- 스트림은 처음 n개 요소를 제외한 스트림을 반환하는 skip(n) 메서드를 지원함.
List<Dish> dishes2 = specialMenu.stream()
.filter(dish -> dish.getCalories() > 300)
.skip(2)
.collect(Collectors.toList());
5.3 매핑
5.3.1 스트림의 각 요소에 함수 적용하기
- 스트림은 함수를 인수로 받는 map 메서드를 지원함.
- 인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑됨.
List<String> dishName = menu.stream()
.map(Dish::getName)
.collect(Collectors.toList());
5.3.2 스트림 평면화
- flatMap 메서드는 스트림의 각 값을 다른 스트림으로 만든 다음 모든 스트림을 하나의 스트림으로 연결하는 기능을 수행.
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs = numbers1.stream()
.flatMap(i -> numbers2.stream().map(j -> new int[] {i, j}))
.filter(ints -> (ints[0] + ints[1] % 3 == 0))
.collect(Collectors.toList());
5.4 검색과 매칭
5.4.1 프레디케이트가 적어도 한 요소와 일치하는지 확인
- 프레디케이트가 주어진 스트림에서 적어도 한 요소와 일치하는지 확인할 때 anyMatch 메서드를 이용함.
- 하나라도 있으면 true를 반환함.
if (menu.stream().anyMatch(Dish::isVegetarian)) {
System.out.println("The menu is (somewhat) vegetarian friendly!");
}
5.4.2 프레디케이트가 모든 요소와 일치하는지 검사
- allMatch 메서드는 스트림의 모든 요소가 주어진 프레디케이트와 일치하는지 검사함.
boolean isHealthy1 = menu.stream().allMatch(dish -> dish.getCalories() < 1000);
- noneMatch는 주어진 프레디케이트와 일치하는 요소가 없는지 확인함.
boolean isHealthy2 = menu.stream().noneMatch(dish -> dish.getCalories() >= 1000);
- anyMatch, allMatch, noneMatch 세 메서드는 스트림 쇼트서킷 기법을 활용함.
5.4.3 요소 검색
- findAny 메서드는 현재 스트림에서 임의의 요소를 반환함.
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findAny();
5.4.4 첫 번째 요소 찾기
- findFirst()는 스트림에서 첫 번째 요소를 반환하는 메서드.
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree = someNumbers.stream()
.map(n -> n * n)
.filter(n -> n % 3 == 0)
.findFirst();
5.5 리듀싱
- 모든 스트림 요소를 처리해서 값으로 도출하는 연산을 리듀싱 연산이라고 함.
5.5.1 요소의 합
int sum = 0;
for (int x : numbers) {
sum += x;
}
- 위 코드를 reduce 메서드를 이용해서 아래와 같이 표현할 수 있음.
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
- 초기값 0, 두 요소를 조합해서 새로운 값을 만드는 BinaryOperator<T>.
Optional<Integer> sumOptional = numbers3.stream().reduce(Integer::sum);
- 초기값이 없어도 되는데, 없는 경우는 Optional을 반환함. 스트림에 아무 요소도 없는 경우 합계를 반환할 수 없기 때문에 Optional로 반환함.
5.5.2 최대값과 최소값
- 최대값과 최소값을 찾을 때도 reduce를 활용할 수 있음.
Optional<Integer> max = numbers3.stream().reduce(Integer::max);
Optional<Integer> min = numbers3.stream().reduce(Integer::min);
5.6 실전 연습
5.7 숫자형 스트림
5.7.1 기본형 특화 스트림
- 자바 8에서는 세 가지 기본형 특화 스트림을 제공함
- 스트림 API는 박싱 비용을 피할 수 있도록 'int 요소에 특화된 IntStream', 'double 요소에 특화된 DoubleStream', 'long 요소에 특화된 LongStream'을 제공함.
- 각각의 인터페이스는 숫자 스트림의 합계를 계산하는 sum, 최댓값 요소를 검색하는 max 같이 자주 사용하는 숫자 관련 리듀싱 연산 수행 메서드를 제공함. 또한 필요할 때 다시 객체 스트림으로 복원하는 기능도 제공함.
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
- 스트림을 특화 스트림으로 변환할 때는 mapToInt, mapToDouble, mapToLong 세 가지 메서드를 가장 많이 사용함.
- 이들 메서드는 Stream<T> 대신 특화된 스트림을 반환함.
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
- boxed 메서드를 이용하면 특화 스트림에서 일반 스트림으로 변환할 수 있음.
- Optional 또한 OptionalInt, OptionalDouble, OptionalLong 세 가지 기본형 특화 스트림 버전도 제공함.
5.7.2 숫자 범위
- 자바 8의 IntStream과 LongStream에서는 range와 rangeClosed 두 가지 정적 메서드를 제공함.
- 두 메서드는 모두 첫 번째 인수로 시작값을, 두 번째 인수로 종료값을 가짐.
- range 메서드는 시작값과 종료값이 결과에 포함되지 않는 반면 rangeClosed는 시작값과 종료값이 결과에 포함됨.
IntStream evenNumbers = IntStream.rangeClosed(1, 100)
.filter(n -> n % 2 == 0);
5.8 스트림 만들기
5.8.1 값으로 스트림 만들기
- 임의의 수를 인수로 받는 정적 메서드 Stream.of를 이용해서 스트림을 만들 수 있음.
Stream<String> stream = Stream.of("Modern ", "Java ", "In ", "Action");
5.8.2 null이 될 수 있는 객체로 스트림 만들기
Stream<String> homeValueStream = Stream.ofNullable(System.getProperty("home"));
5.8.3 배열로 스트림 만들기
- 배열을 인수로 받는 정적 메서드 Arrays.stream을 이용해서 스트림을 만들 수 있음.
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
5.8.4 파일로 스트림 만들기
- Files.lines로 파일의 각 행 요소를 반환하는 스트림을 얻을 수 있음.
5.8.5 함수로 무한 스트림 만들기
- 스트림 API는 함수에서 스트림을 만들 수 있는 두 정적 메서드 Stream.iterate와 Stream.generate를 제공함.
- 두 연산을 이용해서 무한 스트림, 크기가 고정되지 않은 스트림을 만들 수 있음.
- iterate 메서드는 초기값과 람다를 인수로 받아서 새로운 값을 끊임없이 생산할 수 있음.
- generate 메서드도 무한 스트림을 만들 수 있음. 그러나 generate는 생산된 값을 연속적으로 계산하는 것이 아니라, Supplier<T>를 인수로 받아서 새로운 값을 생성해냄.
5.9 마치며
- 스트림 API를 이용하면 복잡한 데이터 처리 질의를 표현할 수 있음.
- filter, distinct, takeWhile, dropWhile, skip, limit 메서드로 스트림을 필터링하거나 자를 수 있음.
- 소스가 정렬되어 있다는 사실을 알고 있을 때 takeWhile과 dropWhile 메소드를 효과적으로 사용할 수 있음.
- map, flatMap 메서드로 스트림의 요소를 추출하거나 변환할 수 있음.
- findFirst, findAny 메서드로 스트림의 요소를 검색할 수 있음. allMatch, noneMatch, anyMatch 메서드를 이용해서 주어진 프레디케이트와 일치하는 요소를 스트림에서 검색할 수 있음.
- 이들 메서드는 쇼트서킷 (short-circuit), 즉 결괄르 찾는 즉시 반환하며, 전체 스트림을 처리하지는 않음.
- reduce 메서드로 스트림의 모든 요소를 반복 조합하며 값을 도출할 수 있음. 예를 들어 reduce로 스트림의 최댓값이나 모든 요소의 합계를 계산할 수 있음.
- filter, map 등은 상태를 저장하지 않는 상태 없는 연산임. reduce 같은 연산은 값을 계산하는 데 필요한 상태를 저장함. sorted, distinct 등의 메서드는 새로운 스트림을 반환하기에 앞서 스트림의 모든 요소를 버퍼에 저장해야 함. 이런 메서드를 상태 있는 연산이라고 부름.
- IntStream, DoubleStream, LongStream은 기본형 특화 스트림임. 이들 연산은 각각의 기본형에 맞게 특화되어 있음.
- 컬렉션 뿐 아니라 값, 배열, 파일, iterate와 generate 같은 메서드로도 스트림을 만들 수 있음.
- 무한한 개수의 요소를 가진 스트림을 무한 스트림이라 함.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 프로그래머스 Level 1
- 인터셉터
- 논블로킹
- non-blocking
- http://www.nextree.co.kr/p6960/
- 코딩테스트 고득점 Kit
- 비동기
- 프로그래머스
- blocking
- 동기
- 해시
- Asynchronous
- Filter
- 스택/큐
- 필터
- Synchronous
- 블로킹
- Handler Interceptor
- 핸들러 인터셉터
- a
- 프로그래머스 Level 3
- 프로그래머스 Level 2
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함