모던 자바 인 액션 5장에서는 스트림 활용하는 방법에 대해 소개한다.
스트림 API 가 지원하는 연산들에 대해 자세히 알아본다.
5.1 필터링
스트림 요소를 선택하는 방법
filter
메서드- 전체 스트림을 반복
Predicate<T>
를 인수로 받아 일치하는 모든 요소를 포함하는 스트림 반환
distinct
메서드- 고유 요소 필터링, 중복 제거 (
hashCode
,equals
로 결정)
- 고유 요소 필터링, 중복 제거 (
5.2 스트림 슬라이싱 (자바 9)
스트림 요소를 선택하거나 스킵하는 방법
takeWhile
Predicate<T>
를 인수로 받아 일치하는 요소들을 포함한 스트림 반환filter
와 다르게 정렬된 리스트를 대상으로 하여 일치하지 않는 경우 반복 작업을 중단
dropWhile
takeWhile
와 반대로 처음으로 일치하지 않는 지점까지의 이전 요소들을 제거하고 남은 모든 요소 반환
limit(n)
long
타입을 인수로 받아 요소 n 개 반환
skip(n)
- 처음
n
개 요소를 제외한 스트림을 제외한 스트림 반환 - 주어진
n
이 요소의 갯수보다 크면 빈 스트림 반환
- 처음
5.3 매핑
특정 객체에서 특정 데이터를 선택하는 기능
map
- 함수를 인수로 받아 각 요소에 적용. 그 결과는 새로운 요소로 매핑된다.
- 다른
map
메서드와 연결(chaining) 가능
flatMap
- 스트림의 각 요소들을 다른 스트림으로 만들어서 하나의 스트림으로 연결
5.4 검색과 매칭
anyMatch
- 적어도 한 요소가 주어진
Predicate
와 일치하는지 확인
- 적어도 한 요소가 주어진
allMatch
- 모든 요소가 주어진
Predicate
와 일치하는지 확인
- 모든 요소가 주어진
noneMatch
allMatch
와 반대 연산- 주어진
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)을 제공한다.
IntStream
DoubleStream
LongSteam
기본형 특화 스트림
- 숫자 스트림으로 매핑
mapToInt
mapToDouble
mapToLong
- 객체 스트림으로 복원
boxed
- 특화 스트림을 일반스트림으로 변환
- 기본값: Optional 기본형 특화 스트림 버전
OptionalInt
OptionalDouble
OptionalLong
숫자 범위
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.lines
Stream
은AutoCloseable
인터페이스를 구현하고 있으므로try
블록 내 자원은 자동으로 관리
- 함수로 무한 스트림 만들기
- 요청할 때마다 값을 생성
- 끝이 없으므로 무한 스트림(infinite stream) 또는 언바운드 스트림(unbounded stream) 이라고 표현
- 무한한 값이 출력되지 않도록 보통
limit(n)
메서드를 사용 Stream.iterate
- 초깃값과 람다(
UnaryOperator<T>
)를 인수로 받아 연속적으로 값을 생성 - 자바 9 에서는
Predicate
도 추가로 받아 언제까지 수행할 것인지 지정 가능
- 초깃값과 람다(
Stream.generate
- 연속적이지 않은 새로운 값을 계속 생성 가능 (
Supplier<T>
을 인수로 받음)
- 연속적이지 않은 새로운 값을 계속 생성 가능 (