참고 : 모던 자바 인 액션
정의
- 데이터 처리 연산을 지원하도록 소스에서 추출된 연속 요소
정의를 조금 더 디테일하게 살펴보자.
연속 요소
- 컬렉션과 마찬가지로, 특정 요소 형식으로 이루어진 연속된 값 집합의 인터페이스
- 컬렉션은 ArrayList를 사용할 지, LinkedList를 사용할지 고민한다.
- 주로 시간과 공간의 복잡성과 관련된 요소 저장 및 접근 연산이 주
- 스트림은 filter, sorted, map처럼 표현 계산식이 주를 이룬다
- 컬렉션의 주제는 ‘데이터’, 스트림의 주제는 ‘계산’
소스
- 컬렉션, 배열, I/O 자원 등의 데이터 제공 소스로부터 데이터를 소비
- 예를 들어 리스트로 스트림을 만들면 스트림의 요소는 리스트의 요소와 같은 순서 유지
데이터 처리 연산
- filter, map, reduce, find, match, sort 등으로 데이터를 조작한다.
- 스트림이 제공하는 많은 메서드는 java api document를 참고하자.
파이프라이닝(Pipelining)
- 스트림 연산끼리 연결해서 커다란 파이프 라인을 구성
- 게으름, 쇼트서킷 같은 최적화를 얻을 수 있다.
내부 반복
- 외부 반복이 아닌 내부에서 반복문 등이 실행
List<String> threeHighCaloricDishNames = menu.stream() .filter(dish -> dish.getCalories() > 300) .map(Dish::getNAme) .limit(3) .collect(toList()); /** 1. menu로부터 stream을 만들어 2. 300 칼로리 이상의 dish로 필터링하고 3. 그들의 이름을 받아서 4. 선착순 3개를 5. 리스트로 반환하여 저장 **/
- 데이터 소스는 menu가 되고
- filter, map, limit, collect가 데이터 처리 연산이다.
- collect를 제외한 모든 연산이 파이프라인을 형성
- 파이프라인은 소스에 적용하는 질의같은 존재라고 생각하자.
컬렉션과 스트림
- DVD와 인터넷 스트리밍을 비교해보자.
- DVD
- 어떤 영화가 저장되있다 = 영화의 전체가 저장되어 있다. 이를 컬렉션으로 보자
- 인터넷 스트리밍
- 사용자가 시청하는 부분의 몇 프레임을 미리 내려받는다.
- 다른 대부분의 값을 처리하지 않은 상태에서 미리 내려받은 프레임부터 재생
핵심 : 데이터를 언제 계산하느냐
- 컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조.
- 적극적 생성 = 모든 값을 계산할 때까지 기다린다.
- 스트림은 이론적으로 요청할 때만 요소를 계산
- 게으른 생성 : 필요할 때만 값을 계산한다.
스트림은 딱 한 번만 탐색할 수 있다
- 한 번 탐색된 스트림의 요소는 사라진다.
- 다시 탐색하려면, 새로운 스트림을 만들어야 한다.
외부 반복과 내부 반복
- 외부 반복은 for문을 명시적으로 사용한 것과 같음
- 또한 병렬성을 스스로 관리해야함
- 내부 반복은 반복자가 필요없다.
- 내부 반복의 장점
- 작업을 병렬로 처리하거나, 최적화된 다양한 순서로 처리할 수 있다.
// 외부 반복
List<String> highCaloriesDishes = new ArrayList<>();
Iterator<String> iterator = menu.iterator();
while(iterator.hasNext()) {
Dish dish = iterator.next();
if (dish.getCalories() > 300 ) {
highCaloricDishes.add(d.getName());
}
}
// 내부 반복
List<String> highCaloriesDishes =
menu.stream()
.filter(dish -> dish.getCalories > 300)
.collect(toList());
스트림 연산 : 상태 없음과 상태 있음
- map, filter 등은 입력 스트림에서 각 요소를 받아 0 또는 결과를 출력 스트림으로 보낸다.
- 사용자가 제공한 람다나 메서드 참조가 내부적인 가변 상태를 갖지 않는다는 가정 하에
- 이들은 내부 상태를 갖지 않는 연산(stateless operation) 이라고 한다.
- reduce, sum, max 같은 연산은 결과를 누적할 내부 상태가 필요하다.
- 이런 내부 상태의 크기는 한정되어 있다.
- 어떤 요소를 출력 스트림으로 추가하려면 모든 요소가 버퍼에 추가되어 있어야 한다.
- 이들을 내부 상태를 갖는 연산 (stateful operation)이라고 한다.
Uploaded by Notion2Tistory v1.1.0