3-1 스트림이란?
→ 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소
특징
- 선언형 : 더 간결하고 가독성이 좋아진다.
- 조립할 수 있음 : 유연성이 좋아진다.
- 병렬화 : 성능이 좋아진다.
3-2 스트림 시작하기
- 연속된 요소 : 특정 요소 형식으로 이루어진 연속된 값 집합의 인터페이스
- 소스 : 컬렉션, 배열, I/O 자원 등의 데이터 제공 소스로부터 데이터를 소비한다 / 정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지된다.
- 데이터 처리 연산 : 함수형 프로그래밍 언어에서 지원하는 연산과 데이터베이스와 비슷한 연산을 지원한다. (filter, map, reduce, find, match, sort) / 스트림 연산은 순차적, 또는 병렬로 실행할 수 있다.
스트림 의 중요한 특징
- 파이프 라이닝 : 대부분의 스트림 연산은 스트림 연산끼리 연결해서 커다란 파이프 라인을 구성할 수 있도록 자신을 반환한다.
- 내부 반복 : 반복자를 이용해서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복을 지원한다.
예시)
스트림 특징
import static java.util.stream.Collectors.toList;
List<String> threeHighCaloricDishNames =
menu.stream() //메뉴(요리 리스트)에서 스트림을 얻는다
.filter(dish -> dish.getCalories() > 300) //파이프라인 연산 만들기, 고칼로리 요리를 필터링한다.
.map(Dish::getName) //요리명 추출
.limit(3) //선착순 3개만
.collect(toList()); //결과를 다른 리스트로 저장 / 반환
3-3 스트림과 컬렉션
→ 기존 컬렉션과 새로운 스트림 모두 연속된(순차적으로 값에 접근) 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공
특징
1) 딱 한 번만 탐색할 수 있다.
→ 탐색된 스트림의 요소는 소비되어 다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 만들어야 한다.
2) 외부 반복과 내부 반복
→ 외부반복 : 명시적으로 컬렉션 항목을 가져와서 처리 (컬렉션)
내부반복 : 반복을 알아서 처리하고 결과 스트림 값을 어딘강 저장 (스트림)
* 내부 반복의 장점
(1) 작업을 투명하게 병렬로 처리하거나 더 최적화된 다양한 순서로 처리할 수 있다.
(2) 데이터의 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택한다.
3-4 스트림 연산
→ 중간연산(연결할 수 있는 연산)과 최종 연산(스트림을 닫는 연산)이 있다.
중간연산
→ 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다.
연산형식반환 형식연산의 인수함수 디스크럽터
filter | 중간 연산 | Stream<T> | Predicate<T> | T -> boolean |
map | 중간 연산 | Stream<R> | Function< T , R > | T -> R |
limit | 중간 연산 | Stream<T> | ||
sorted | 중간 연산 | Stream<T> | Comparator<T> | ( T , T ) -> int |
distinct | 중간 연산 | Stream<T> |
최종연산
→ 최종 연산에 의해 List, Integer, void등 스트림 이외의 결과가 반환
연산형식반환형식목적
forEach | 최종 연산 | void | 스트림의 각 요소를 소비하면서 람다를 적용한다. |
count | 최종 연산 | long(generic) | 스트림의 요소 개수를 반환한다. |
collect | 최종 연산 | 스트림을 리듀스해서 리스트, 맵, 정수 형식의 컬렉션을 만든다. |
스트림 이용
- 질의를 수행할 데이터 소스
- 스트림 파이프라인을 구성할 중간 연산 연결
- 스트림 파이프라인을 실행하고 결과를 만들 최종 연산
정리
- 스트림은 소스에서 추출된 연속 요소로, 데이터 처리 연산을 지원한다.
- 스트림은 내부 반복을 지원한다. 내부 반복은 filter, map, sorted등의 연산으로 반복을 추상화한다.
- 스트림에는 중간 연산과 최종 연산이 있다.
- 중간 연산은 filter, map처럼 스트림을 반환하면서 다른 연산과 연결되는 연산이다. 중간 연산을 이용해서 파이프 라인을 구성할 수 있지만 중간 연산으로는 어떤 결과도 생성할 수 없다.
- forEach나 count처럼 스트림 파이프라인을 처리해서 스트림이 아닌 결과를 반환하는 연산을 최종 연산이라고 한다.
연산형식반환 형식사용된 함수형 인터페이스 형식함수 디스크립터작업연산형식반환 형식사용된 함수형 인터페이스 형식함수 디스크립터작업
filter | 중간 연산 | Stream<T> | Predicate<T> | T -> boolean | 요소들을 조건에 따라 걸러내는 작업 |
distinct | 중간 연산 (상태가 있는 언바운드 → 내부 상태가 한정되어있지 않음) |
Stream<T> | 중복을 제거하여 새로운 스트림 리턴 | ||
skip | 중간 연산 (상태가 있는 바운드) |
Stream<T> | long | 일정 개수만큼 아이템을 건너띄고 나머지 요소들로 스트림을 생성 | |
limit | 중간 연산 (상태가 있는 바운드) |
Stream<T> | long | 스트림에서 일정 개수만큼 가져와서 새로운 스트림 리턴 | |
map | 중간 연산 | Stream<R> | Function<T, R> | T -> R | 요소들을 특정 조건에 해당하는 값으로 변환 |
flatMap | 중간 연산 | Stream<R> | Function<T, Stream<R>> |
T -> Stream<R> | 스트림의 형태가 배열과 같을 때 모든 원소를 안일 원소 스트림으로 반환 |
sorted | 중간 연산 (상태가 있는 언바운드 → 내부 상태가 한정되어있지 않음) |
Stream<T> | Comparator<T> | (T, T) -> int | 요소들을 정렬해주는 작업 |
anyMatch | 최종 연산 | boolean | Predicate<T> | T -> boolean | 최소한 한 개의 요소가 주어진 조건에 만족하는지 검사 |
noneMatch | 최종 연산 | boolean | Predicate<T> | T -> boolean | 모든 요소들이 주어진 조건을 만족하지 않는지 조사 |
allMatch | 최종 연산 | boolean | Predicate<T> | T -> boolean | 모든 요소들이 매개값으로 주어진 조건을 만족하는지 조사 |
findAny | 최종 연산 | Optional<T> | 스트림의 순서와 관계없이 먼저 찾아지는 객체를 리턴 | ||
findFirst | 최종 연산 | Optional<T> | 순서상 가장 첫 번째 있는 것을 리턴 | ||
forEach | 최종 연산 | void | Consumer<T> | T -> void | 지정된 작업을 스트림의 모든 요소에 대해 수행 |
collect | 최종 연산 | R | Collector<T, A, R> | 미리 작성된 다양한 종류의 컬렉터로 리턴 | |
reduce | 최종 연산 (상태 있는 바운드) |
Optional<T> | BinaryOperator<T> | (T, T) -> int | 스트림의 요소를 줄여나가면서 연산을 수행하고 최종 결과를 리턴 → 처음 두 요소를 가지고 연산한결과를 가지고 다음 요소와 연산 |
count | 최종 연산 | long | 스트림 요소의 개수 리턴 |
'Modern java in action' 카테고리의 다른 글
5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2021.08.22 |
---|---|
[modern java in action] stream(5) (0) | 2021.06.24 |
[modern java in action] stream(4) (0) | 2021.06.24 |
[modern java in action] stream(3) (0) | 2021.06.24 |
[Modern java in action] Stream(2) (0) | 2021.06.24 |
댓글