모던 자바 인 액션 5장에서는 스트림 활용하는 방법에 대해 소개한다.
스트림 API 가 지원하는 연산들에 대해 자세히 알아본다.
5.1 필터링
스트림 요소를 선택하는 방법
filter메서드- 전체 스트림을 반복
Predicate<T>를 인수로 받아 일치하는 모든 요소를 포함하는 스트림 반환
distinct메서드- 고유 요소 필터링, 중복 제거 (
hashCode,equals로 결정)
- 고유 요소 필터링, 중복 제거 (
5.2 스트림 슬라이싱 (자바 9)
스트림 요소를 선택하거나 스킵하는 방법
takeWhilePredicate<T>를 인수로 받아 일치하는 요소들을 포함한 스트림 반환filter와 다르게 정렬된 리스트를 대상으로 하여 일치하지 않는 경우 반복 작업을 중단
dropWhiletakeWhile와 반대로 처음으로 일치하지 않는 지점까지의 이전 요소들을 제거하고 남은 모든 요소 반환
limit(n)long타입을 인수로 받아 요소 n 개 반환
skip(n)- 처음
n개 요소를 제외한 스트림을 제외한 스트림 반환 - 주어진
n이 요소의 갯수보다 크면 빈 스트림 반환
- 처음
5.3 매핑
특정 객체에서 특정 데이터를 선택하는 기능
map- 함수를 인수로 받아 각 요소에 적용. 그 결과는 새로운 요소로 매핑된다.
- 다른
map메서드와 연결(chaining) 가능
flatMap- 스트림의 각 요소들을 다른 스트림으로 만들어서 하나의 스트림으로 연결
5.4 검색과 매칭
anyMatch- 적어도 한 요소가 주어진
Predicate와 일치하는지 확인
- 적어도 한 요소가 주어진
allMatch- 모든 요소가 주어진
Predicate와 일치하는지 확인
- 모든 요소가 주어진
noneMatchallMatch와 반대 연산- 주어진
Predicate와 일치하는 요소가 없는지 확인
findAny- 현재 스트림에서 임의의 요소 반환
- 다른 스트림 연산과 연결해서 사용 가능
Optional반환
findFirst- 논리적인 아이템 순서로 정렬된 데이터의 첫번째 요소 반환
Optional반환
쇼트서킷 평가
자바의 &&, || 와 같은 연산
전체 스트림을 처리하지 않아도 결과 반환 가능
원하는 요소를 찾으면 즉시 결과 반환
ex) allMatch, noneMatch, findFirst, findAny, limit…
Optional
- 값의 존재 여부를 표현하는 컨테이너 클래스
- 에러를 일으킬 수 있는
null대신 사용 - 값의 유무에 따라 처리를 강제하는 기능 제공
isPresent(): 값이 존재하면 참(true), 없으면 거짓(false) 반환ifPresent(Consumer<T> block): 값이 존재하면 주어진 블록 실행T get(): 값이 존재하면 값 반환, 없으면NoSuchElementException발생T orElse(T other): 값이 존재하면 값 반환, 없으면 기본값(other) 반환
5.5 리듀싱
스트림의 모든 요소를 반복적으로 처리하여 값으로 도출하는 연산 (종이를 작은 조각이 될 때까지 접는 것과 비슷해서 폴드라고도 부름)
리듀스 인수
- 초깃값
- 스트림에 요소가 없는 경우가 있기 때문에 초깃값이 없으면
Optional<T>반환
- 스트림에 요소가 없는 경우가 있기 때문에 초깃값이 없으면
-
스트림의 두 요소를 합쳐서 하나의 값으로 만드는 데 사용할 람다
- 예시
- 요소의 합
numbers.stream().reduce(0, (a, b) -> a + b);- 초깃값 0
- 람다 표현식으로 두 요소를 합함
- 최댓값 최솟값
numbers.stream().reduce(Integer::max);numbers.stream().reduce(Integer::min);
- 요소의 합
| 연산 | 형식 | 반환 형식 | 함수형 인터페이스 형식 |
|---|---|---|---|
| filter | 중간 연산 | Stream |
Predicate |
| distinct | 중간 연산 | Stream |
|
| takeWhile | 중간 연산 | Stream |
Predicate |
| dropWhile | 중간 연산 | Stream |
Predicate |
| skip | 중간 연산 | Stream |
long |
| limit | 중간 연산 | Stream |
long |
| map | 중간 연산 | Stream |
Function<T, R> |
| flatMap | 중간 연산 | Stream |
Function<T, Stream |
| sorted | 중간 연산 | Stream |
Comparator |
| anyMatch | 최종 연산 | boolean | Predicate |
| noneMatch | 최종 연산 | boolean | Predicate |
| allMatch | 최종 연산 | boolean | Predicate |
| findAny | 최종 연산 | Optional |
|
| findFirst | 최종 연산 | Optional |
|
| forEach | 최종 연산 | void | Consumer |
| collect | 최종 연산 | R | Collector<T, A, R> |
| reduce | 최종 연산 | Optional |
BinaryOperator |
| count | 최종 연산 | long |
5.7 숫자형 스트림
스트림 API 에는 박싱 비용을 피하고 효율적으로 처리할 수 있도록 3가지 기본형 특화 스트림(primitive stream specialization)을 제공한다.
IntStreamDoubleStreamLongSteam
기본형 특화 스트림
- 숫자 스트림으로 매핑
mapToIntmapToDoublemapToLong
- 객체 스트림으로 복원
boxed- 특화 스트림을 일반스트림으로 변환
- 기본값: Optional 기본형 특화 스트림 버전
OptionalIntOptionalDoubleOptionalLong
숫자 범위
IntStream, LongStream 에서의 range, rangeClosed 정적 메서드로 특정 범위의 숫자를 이용할 수 있다.
두 메서드 모두 첫번째 인수로 시작값, 두번째 인수로 종료값을 받는다.
range- 종료값이 포함되지 않음
rangeClosed- 종료값이 결과에 포함
5.8 스트림 만들기
- 값으로 스트림 만들기
Stream.of(T... values)Stream.empty()(빈 스트림)
null이 될 수 있는 스트림 (자바 9 추가)Stream.ofNullable(T t)(null이라면 빈 스트림)
- 배열로 스트림 만들기
Arrays.stream(array)(기본형도 가능)
- 파일로 스트림 만들기
Files.linesStream은AutoCloseable인터페이스를 구현하고 있으므로try블록 내 자원은 자동으로 관리
- 함수로 무한 스트림 만들기
- 요청할 때마다 값을 생성
- 끝이 없으므로 무한 스트림(infinite stream) 또는 언바운드 스트림(unbounded stream) 이라고 표현
- 무한한 값이 출력되지 않도록 보통
limit(n)메서드를 사용 Stream.iterate- 초깃값과 람다(
UnaryOperator<T>)를 인수로 받아 연속적으로 값을 생성 - 자바 9 에서는
Predicate도 추가로 받아 언제까지 수행할 것인지 지정 가능
- 초깃값과 람다(
Stream.generate- 연속적이지 않은 새로운 값을 계속 생성 가능 (
Supplier<T>을 인수로 받음)
- 연속적이지 않은 새로운 값을 계속 생성 가능 (