일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 클린코드
- 디자인 패턴
- domain
- Java
- spring Batch
- Clean Code
- facade pattern
- Stream
- Java8
- Was
- CQRS
- spring
- 스트림
- Java in action
- Java8 in action
- Template Method Pattern
- 자바
- spring boot
- 자바의 신
- 자바8인액션
- ddd
- web
- 패스트캠퍼스
- jsp
- Java 8 in action
- head first
- 자바8
- AWS101
- SERVLET
- Design Pattern
- Today
- Total
주난v 개발 성장기
[자바 8인 액션] 4장. 스트림 소개 본문
컬렉션은 데이터를 그룹화하고 처리할 수 있다. 프로그래밍 작업에 필수적인 요소다.
하지만, 특정 조건에 대한 처리에는 약하다.
많은 요소를 포함하는 커다란 컬렉션은 어떻게 처리할까?
-> 성능을 높이려면 멀티코어 환경에서 병렬로 컬렉션 요소를 처리해야 한다.
하지만, 병렬 처리 코드를 구현하는 것은 어렵다.
따라서, "스트림"을 사용하는 것이 답이다.
스트림이란 무엇인가?
- 자바 API에 추가된 기능, 스트림을 이용하면 선언형으로 컬렉션 데이터를 처리할 수 있다.
또한 멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있다.
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish d : menu) {
if (d.getCalories() < 400) {
lowCaloricDishes.add(d);
}
}
//자바 8
List<String> lowCaloricDishesName = menu.stream().filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
filter(or sorted, map, collect) 같은 연산은 고수준 빌딩 블록으로 이루어져 있으므로 특정 스레딩 모델에 제한되지 않고, 자유롭게 사용
-> 데이터 처리 과정을 병렬화하면서 스레드와 락을 걱정할 필요가 없다.
스트림 API의 특징
1. 선언형 : 더 간결하고, 가독성이 좋다.
2. 조립할 수 있다 : 유연성
3. 병렬화 : 성능이 좋아진다.
스트림이란?
- 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소
데이터 처리 연산 : filter, map, reduce, find, match, sort
소스 : 컬렉션 or 배열 or I/O 자원 등의 데이터 제공 소스로부터 데이터를 소비
파이프라이닝 : 스트림 연산은 스트림 연산끼리 연결해서 커다란 파이프라인 구성하여 스트림 자신을 반환
내부 반복 : 스트림은 내부 반복 (컬렉션은 외부반복)
List<String> threeHighCaloricDishNames =
menu.stream()
.filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
filter : 람다를 인수로 받아 스트림에서 특정 요소를 제외시킨다.(필터링)
map : 람다를 이용해서 한 요소를 다른 요소로 변환하거나 정보를 추출한다. (Dish::getName --> 요리명 추출)
limit : 정해진 개수 이상의 요소가 스트림에 저장되지 못하게 스트림 크기를 축소한다.
collect : 스트림을 다른 형식으로 변환한다.
스트림과 컬렉션
차이 : 데이터를 언제 계산하느냐의 차이
컬렉션 : 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료 구조.
즉, 모든 컬렉션의 요소는 컬렉션에 담기기 전에 계산되어야 한다.
컬렉션에 요소를 추가하거나 삭제할 수 있다. 이러한 연산을 수행할 때마다 컬렉션의 모든 요소를 메모리에 저장해야하며,
컬렉션에 추가하려는 요소는 미리 계산되어야 한다.
스트림 : 요청할 때만 요소를 계산
스트림에 요소를 추가하거나 제거할 수 없다.
사용자가 요청하는 값만 스트렘에서 추출하는 것이 핵심
스트림은 생산자와 소비자 관계를 형성한다.
스트림은 게으르게 만들어지는 컬렉션과 같다. 즉, 사용자가 데이터를 요청할 때만 값을 계산한다.
반면, 컬렉션은 적극적으로 생성된다.
스트림은 딱 한 번만 탐색할 수 있다.
탐색된 스트림의 요소는 소비된다.
다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 만들어야 한다.
(그러려면 컬렉션처럼 반복 사용할 수 있는 데이터 소스여야 한다.)
만일 데이터 소스가 I/O 채널이라면, 소스를 반복 사용할 수 없으므로 새로운 스트림을 만들 수 없다.
스트림 : 시간적으로 흩어진 값의 집합
컬렉션 : 특정 시간에 모든 것이 존재하는 공간
컬렉션 인터페이스를 사용하려면 사용자가 직접 요소를 반복해야 한다.(for-each..따라서 외부 반복)
반면 스트림 라이브러리는 알아서 처리하고..내부반복을 사용한다.
스트림 연산
List<String> threeHighCaloricDishNames =
menu.stream()
.filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
- filter, map, limit은 서로 연결되어 파이프라인을 형성
- collect로 파이프라인을 실행한 다음에 닫는다.
연결할 수 있는 스트림 연산을 중간 연산, 스트림 닫는 연산을 최종 연산이라고 한다.
중간 연산
- filter, sorted같은 중간 연산은 다른 스트림을 반환
- 여러 중간 연산을 연결해서 질의를 만들 수 있다.
중간 연산의 중요한 특징
- 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하진 않는다. 즉, 게으르다.
- 중간 연산을 합친 다음에 합쳐진 중간 연산을 최종 연산으로 한번에 처리
스트림의 게으른 특성으로 최적화 효과를 얻을 수 있다.
1. 300칼로리가 넘는 요리는 여러 개지만, 처음 3개만 선택! 이는 limit 연산 그리고 쇼트서킷이라 불리는 기법
2. filter, map은 서로 다른 연산이지만, 한 과정으로 병합되었다.(루프 퓨전)
최종 연산
스트림 파이프라인에서 결과를 도출
보통 List, Integerm void 등 스트림 이외의 결과가 반환.
스트림 이용하기
스트림 파이프라인 개념은 빌더 패턴과 비슷.
요약
-
스트림은 소스에서 추출된 연속 요소로, 데이터 처리 연산을 지원한다.
-
내부 반복을 지원. filter, map, sorted등의 연산으로 반복을 추상화한다.
- 스트림에는 중간 연산과 최종 연산이 있다.
-
filter, map처럼 스트림을 반환하면서 다른 연산과 연결될 수 있는 연산은 중간 연산이다.
-
중간 연산을 이용해서 파이프라인을 구성할 수 있지만, 중간 연산으로는 어떠한 결과도 생성할 수 없다.
-
스트림 파이프라인을 처리해서 스트림이 아닌 결과를 반환하는 연산을 최종 연산이라고 한다.
-
스트림의 요소는 요청할 때만 계산된다.
'개발 성장기 > JAVA' 카테고리의 다른 글
[자바 8인 액션] 6장. 스트림으로 데이터 수집 (0) | 2020.07.21 |
---|---|
[자바 8인 액션] 5장. 스트림 활용 (0) | 2020.07.15 |
[자바 8인 액션] 3장. 람다 표현식 (0) | 2020.07.01 |
[자바 8 인 액션] 2장. 동작 파라미터화 코드 전달 (0) | 2020.06.17 |
[자바 8 인 액션] 1장. 자바 8을 눈여겨봐야 하는 이유 (0) | 2020.06.13 |