스트림 소개
- 스트림을 이용하면 선언형으로 컬렉션 데이터 처리 가능
- 병렬 처리 기능
예시
// 1. 필터링
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish d: menu) {
if(d.getCalories() < 400) {
lowCaloricDishes.add(d);
}
}
// 2. 정렬
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
public int compare(Dish d1, Dish d2) {
return Integer.compare(d1.getCalories(), d2.getCalories());
}
});
//3. 요리 이름 추출
List<String> lowCaloricDisheName = new ArrayList<>();
for(Dish d: lowCaloricDishes) {
lowCaloricDishesName.add(d.getName());
}
- 구조를 파악하기 위해서 모든 for loop의 몸통을 살펴야함
자바 8은 세부구현을 라이브러리 내에서 모두 처리한다.
List<String> lowCaloricDishesName =
menu.stream()
.filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList())
병럴 처리시, stream대신 parallelStream() 사용 - 7장
스트림 장점
- 선언형 (가독성)
- 조립 (유연성)
- 병렬화 (성능)
- 파이프 라인 형성
파이프라인
파이프라인을 쓰면, 컴퓨터 구조는 프로세서가 산술연산을 수행하는 동안에 다음번 명령어를 가져올 수 있으며,
그것을 다음 명령어 연산이 수행될 수 있을 때까지 프로세서 근처의 버퍼에 가져다놓는다.
명령어를 가져오는 단계는 끊임없이 계속된다. 그 결과, 주어진 시간동안에 수행될 수 있는 명령어의 수가 증가한다.
명령어1이 실행되는 동안 명령어2가 준비되고 실행되는 것
4.2 컬렉션 스트림
- Collection에서는 stream을 반환하는
stream 메서드
- 스트림이란?
데이터 처리
연산
을 지원하도록소스
에서 추출된연속된 요소
- 데이터 처리 연산
- 람다
- 디비와 비슷한 연산 지원 (filter, map, reduce, find, match, sort 등)으로 데이터 조작
- 순차, 병렬 실행 가능
- 소스
- 컬렉션, 배열, I/O 자원 등의 데이터 제공 소스로부터
데이터를 소비
- 리스트로 스트림을 만들면 순서 유지됨
- 컬렉션, 배열, I/O 자원 등의 데이터 제공 소스로부터
- 파이프라이닝
- 스트림 반환
- laziness, short-circuiting같은 최적화를 얻을 수 있다 (5장)
- 연산 파이프라인은 데이터 소스에 적용하는 디비 질의와 비슷
- 스트림 반환
- 연속된 요소
- 컬렉션 : 요소
저장
, 접근연산 - 스트림 : 요소
계산
- 컬렉션 : 요소
내부 반복
스트림은 내부 반복을 지원한다.
스트림 연산
- filter
- 람다를 인수로 받아 스트림에서 특정 요소를 제외시킨다.
- map
- 람다를 이용해서 한 요소를 다른 요소로 변호나하거나, 정보 추출
- limit
- 스크림 크기 축소
- collect
- 스트림을 다른 형식으로 변환
- filter
4.3 스트림과 컬렉션
- 둘다
연속된
요소 형식의 값을 저장 - 컬렉션
- 모든 값을 메모리에 저장
- 컬렉션의 모든 요소는 추가되기 전에 계산되어야한다.
스트림
- 사용자가 요청한 값만 스트림에서 추출
- 스트림에 요소를 추가, 제거 X
- 게으르게 만들어지는 컬렉션과 같다.
- 사용자가 데이터를 요청할 때만 값을 계산
소수 예제
- 컬렉션은 끝이 없는 모든 소수를 포함하려 할 것 이므로, 무한루프를 돌며 새로운 소수를 계산하고 추가하기 반복
- 영원히 볼 수 없다
- 컬렉션은 끝이 없는 모든 소수를 포함하려 할 것 이므로, 무한루프를 돌며 새로운 소수를 계산하고 추가하기 반복
브라우저 인터넷 검색 예제
- 검색어를 입력하면 모든 검색 결과를 내려받는 것이아니라 10~20개의 결과 요소를 포함하는 스트림을 얻는다.
4.3.1 스트림은 한번만 탐색할 수 있다.
- 탐색된 요소는 소비
- 다시 탐색하려면 초기 데이터 소스에서 `새로운`스트림 생성해야함. 이때, 데이터솟는 반복을 사용할 수 있어야한다.
- 데이터 소스가 I/O 채널이면 소스 반복X, 새루은 스트림 생성X
내부 반복의 이점
요소를 어떻게 반복시킬지는 신경쓰지 않고, 요소 처리 코드에만 집중 할 수 있다.
- 외부 반복자는 요소를 가져오고, 처리하는 것까지 개발자가 작성, 그러나 스트림은 람다식으로 요소 처리 내용만 전달하고, 반복은 컬렉션 내부에서 일어난다.
작업을 투명하게 병렬로 처리
- 더 최적화된 다양한 순서로 처리
- 데이터 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택한다.
- 외부 반복(for-each)은 병렬성 포기 or synchronized 사용
- 요소의 반복 순서를 변경하거나, 멀티 코어 cpu를 최대한 활용하기 위해서 요소를 분배시켜 병렬 작업을 할 수 있도록 도와주기 때문에 순차적 외부 반복자보다 효율적으로 반복시킬 수 있다.
병렬 처리란 (parallel)?
한 가지 작업을 서브 작업으로 나누고, 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는것
병렬 처리 스트림
런타임 시 하나의 작업을 서브 작업으로 자동으로 나누고, 서브 작업의 결과를 자동으로 결합해 최종 결과물 생성
스트림 연산
중간 연산
- 중간 연산은 새로운 스트림을 반환
- 단말 연산을 스트림 파이프라인에 실행하기 전까지 아무 연산도 수행하지 않는다.
- 게으르다
- 중간 연산을 합친 다음에 합쳐진 중간 연산을 최종 연산으로
한번에 처리
- limit : 쇼트커트
- filter + map : 루프 퓨전
최종 연산
- 스트림 파이프라인에서 결과를 도출(스트림이 아닌)
- 단말 연산을 스트림 파이프라인에 실행하기 전까지 아무 연산도 수행하지 않는다.
- 중간 연산 정보를 합친다음 스트림으로 입력받아 한번에 처리한다.
- 최종 연산을 실행하면 스트림 파이프라인은 소비되고, 재사용 할 수 없다. (다시 초기 데이터에서 새로운 스트림을 만들어야함)
- forEach : void반환
- 스트림을 닫을 필요는 없지만, IO채널의 경우에는 close해줘야한다.
'JAVA > JAVA8' 카테고리의 다른 글
[JAVA8] 자바8 기초 (0) | 2018.04.30 |
---|