본문 바로가기

개발공부/JAVA

모던 자바인 액션 : 스트림

4.1 스트림 소개

 

: 자바 애플리케이션의 대부분은 컬렉션을 만들고 처리하는 과정을 포함

: 컬렉션으로 데이터를 그룹화 하고 처리할 수 있음

: 많은 요소를 포함하는 커다란 컬렉션의 경우 성능을 높이려면 멀티코어 아키텍처를 활용해서 병렬로 컬렉션의 요소를 처리해야한다. => 어렵고 복잡함

 

이를 해결하기 위한 : 스트림 등장!

 

스트림이란?

자바 8 API에 추가된 새로운 기능

스트림은 데이터 컬렉션 반복을 멋지고 간편하게 처리하는 기능

멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있음.

 

p136

기존의 코드와 자바 8비교 소스 코드 (.stream() / .parallelStream())

스트림과 파라렐 스트림은 (멀티코어 아키텍쳐에서 병렬로 실행할 수 있음)

 

스트림의 장점  

: 람다식을 사용해서 선언형 코드로 구형할수 있다(요구사항에 쉽게 대응 가능, 간단한 코드로 코드 작성 가능)

: filter, sorted, map, collect 같은 여러 빌딩 블록 연산을 연산해서 복잡한 데이터 처리 파이프라인을 만들 수 있다.

=> 한방에 여러 연산 가능 p138 그림 4-1 참고

 

결과적으로 데이터 처리과정을 병렬화 하면서 스레드와 락을 걱정할 필요가 없어짐.

1. 선언형 : 더 간결하고 가독성이 좋아짐

2. 조립가능 : 유연성이 좋음

3. 병렬화 : 성능이 좋아짐 

 

컬렉션을 제어하는 기타 라이브러리 : 구아바, 아파치, 람다제이

 

4.2 스트림 시작하기 

자바 8 컬렉션에는 스트림을 반환 하는 stream 메서드가 추가됨(java.util.stream.Stream 참고)

스트림이란 정확히 뭘까?

: 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소

 

연속된 요소?

: 컬렉션과 마찬가지로 스트림은 특정 요소 형식으로 이루어진 연속된 값 집합의 인터페이스를 제공.

컬렉션은 자료구조라 arraylist나 linkedlist를 사용에 댜한 시공간 복잡성과 관련 요소 저장 및 접근 연산이 주를 이룸 (데이터)

스트림은 filter, sorted, map 처럼 표현 계산식이 주를 이룸 (계산식)

 

소스?

: 정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지됨. 리스트로 스트림을 만들면 스트림의 요소는 리스트의 요소와 같은 순서를 유지한다.(?)

 

데이터 처리연산?

: filter, map, reduce, find, match, sort 등으로 데이터를 조작할 수 있음.

: 순차적으로 또는 병렬로 실행 할 수 있음

 

스트림의 중요 특징

1. 파이프라이닝(pipelining)

: 대부분의 스트림 연산은 스트림 연산끼리 연결해서 커다란 파이프 라인을 구성할 수 있도록 스트림 자신을 반환함.

: laziness, short-circuiting 같은 최적화도 얻을 수 있음

: 연산 파이프라인은 데이터 소스에 적용하는 데이터베이스 쿼리랑 비슷함.

2. 내부반복

: 반복자를 이용해서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복을 지원함.

 

예제) p142 예시 

stream 객체 생성 =>  필요한 연산 처리(filter, 추출, limit) => list 형태로 반환

 

4.3 스트림과 컬렉션

데이터를 언제 계산하느냐가 가장 큰 차이.

컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 구조 => 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어야함

스트림은 요청할 때만 요소를 계산하는 고정된 자료구조.

 

4.3.1 딱 한번만 탐색할 수 있다.

반복자와 마찬가지로 스트림도 한번만 탐색할 수 있다. 

 

4.3.2 외부반복과 내부반복

외부반복 : 사용자가 직접 요소를 반복하는것(예를 들면 for-each). 병렬성을 스스로 관리해야함

내부반복 : 반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장해줌. 최적화 가능(병렬성 구현을 자동으로 선택함)

=> 자바8에서 컬렉션 인터페이스와 비슷하면서 반복자가 없는 무엇이 필요했다! => 이것이 스트림

예제 p149

 

4.4 스트림 연산

- 중간 연산

: filter, map, limit은 서로 연결되어 파이프라인을 형성한다.

: 중간 연산은 다른 스트림을 반환한다.

: 여러 중간 연산을 연결해서 질의를 만들 수 있다.

: 중간 연산을 합친 다음에 합쳐진 중간 연산을 최종 연산으로 한번에 처리하기 때문 (게.으.름)

: filter, map, limit, sort, distict (p153 표참조)

 

- 최종 연산

: collect로 파이프라인을 실행한 다음에 닫음 (.collect(toList()));

: 스트림 파이프라인에서 결과를 도출한다.

: foreach, count, collect (p153 표참조)

 

4.4.3 스트림 이용하기 

- 질의를 수행할 (컬렉션 같은) 데이터 소스

- 스트림 파이프라인을 구성할 중간 연산 연결

- 스트림 파이프라인을 실행하고 결과를 만들 최종연산