SlideShare a Scribd company logo
1 of 105
Download to read offline
씹고 뜯고 맛보고 즐기는 
스트림 API 
KSUG & 지앤선이 함께하는 테크니컬 세미나 - KSUG에게 듣는 자바 8 이야기
박용권 
KSUG 일꾼단 
: 한국 스프링 사용자 모임(KSUG) 
: 봄싹(SpringSprout) 
: 라 스칼라 코딩단 
http://about.me/arawn 
: twitter / @arawnkr
내 연락처에 등록된 사람들 중 
플로리다에 사는 남자들의 평균 나이는?
명시적 반복을 통해 요구사항 구현… 
List<Contact> contacts = ContactSource.findAll(); 
int manCount = 0; 
int totalAge = 0; 
for(Contact contact : contacts) { 
if("Florida".equals(contact.getState()) 
&& Gender.Male == contact.getGender()) { 
manCount += 1; 
totalAge += contact.getAge(); 
} 
} 
double averageAge = totalAge / manCount;
명시적 반복을 통해 요구사항 구현… 
List<Contact> contacts = ContactSource.findAll(); 
int manCount = 0; 
int totalAge = 0; 
for(Contact contact : contacts) { 
if("Florida".equals(contact.getState()) 
&& Gender.Male == contact.getGender()) { 
manCount += 1; 
totalAge += contact.getAge(); 
명령형 프로그래밍 
} 
} 
double averageAge = totalAge / manCount;
명시적 반복을 통해 요구사항 구현… 
List<Contact> contacts = ContactSource.findAll(); 
int manCount = 0; 
int totalAge = 0; 
for(Contact contact : contacts) { 
if("Florida".equals(contact.getState()) 
&& Gender.Male == contact.getGender()) { 
manCount += 1; 
totalAge += contact.getAge(); 
} 
} 
! 
double averageAge = totalAge / manCount; 
어떻게가 아닌, 무엇을 계산하는지가 중요
스트림 API와 람다 표현식으로 요구사항 구현… 
List<Contact> contacts = ContactSource.findAll(); 
contacts.stream() 
.filter(c -> "Florida".equals(c.getState())) 
.filter(c -> Gender.Male == c.getGender()) 
.mapToInt(c -> c.getAge()) 
.average();
스트림 API와 람다 표현식으로 요구사항 구현… 
List<Contact> contacts = ContactSource.findAll(); 
contacts.stream() 
.filter(c -> "Florida".equals(c.getState())) 
.filter(c -> Gender.Male == c.getGender()) 
.mapToInt(c -> c.getAge()) 
.average(); 
파이프-필터 기반 API
결과 
스트림 API의 처리 흐름 
리듀스 
(연산) 
필터 
(연산) 
맵 
소스 (연산)
스트림과 콜렉션은 다르다 
Collection Stream 
contacts.forEach(c -> { ... }) 
✔ 외부 반복(External Iteration) 
✔ 반복을 통해 생성 
✔ 효율적이고 직접적인 요소 처리 
✔ 유한 데이터 구조 
✔ 반복적 재사용 가능 
✔ 내부 반복(Internal Iteration) 
✔ 반복을 통해 연산 
✔ 파이프-필터 기반 API 
✔ 무한 연속 흐름 데이터 구조 
✔ 재사용 불가 
for(Contact c : contacts) { ... }
스트림 API 맛보기
스트림 API의 목적 
데이터 보관이 아닌 
데이터 처리에 집중
스트림 API의 특징 
반복의 내재화 
✔ 반복 구조 캡슐화(제어 흐름 추상화, 제어의 역전) 
✔ 최적화와 알고리듬 분리 
지연 연산 
✔ 스트림을 반환하는 필터-맵 API는 기본적으로 지연(lazy) 연산 
✔ 지연 연산을 통한 성능 최적화(무상태 중개 연산 및 반복 작업 최소화) 
병렬 처리 
✔ 동일한 코드로 순차 또는 병렬 연산을 쉽게 처리 
✔ 쓰레드에 안전하지 않은 컬렉션도 병렬처리 지원 
✔ 단, 스트림 연산 중 데이터 원본을 변경하면 안된다
스트림 인터페이스: Stream interface 
java.util.stream 
Stream<T> 
IntStream 
LongStream 
DoubleStream
스트림 인터페이스: Stream interface 
Stream<T> 
IntStream 
LongStream 
DoubleStream 
✔ 객체를 요소로 하는 범용 스트림 
✔ int를 요소로 하는 스트림 
✔ long을 요소로 하는 스트림 
✔ double을 요소로하는 스트림
스트림 인터페이스: Stream interface 
Stream<T> 
IntStream 
LongStream 
DoubleStream 
✔ 객체를 요소로 하는 범용 스트림 
✔ int를 요소로 하는 스트림 
✔ long을 요소로 하는 스트림 
✔ double을 요소로하는 스트림
2가지 유형의 스트림 인터페이스 
순차 스트림 
(Sequential Stream) 
stream.parallel() stream.sequential() 
병렬 스트림 
(Parallel Stream)
함수형 인터페이스: Functional interfaces 
java.util.function.* 
✔ 스트림 연산자의 대부분은 인수로 함수형 인터페이스를 받음 
✔ 함수형 인터페이스는 람다 표현식 또는 메소드 표현식으로 사용 
함수형
 인터페이스 설명 
SupplierT T
 타입
 값을
 공급한다. 
ConsumerT T
 타입
 값을
 소비한다. 
BiConsumerT,
 U T와
 U
 타입
 값을
 소비한다. 
PredicateT boolean
 값을
 반환한다. 
ToIntFunctionT 
ToLongFunctionT
  
ToDoubleFunctionT 
T
 타입을
 인자로
 받아
 int,
 long,
 double
 값을
 반환한다. 
IntFunctionR 
LongFunctionR
  
DoubleFunctionR 
int,
 lond,
 double
 값을
 인자로
 받아
 R
 타입
 값을
 반환한다. 
FunctionT,
 R T
 타입을
 인자로
 받고
 R
 타입을
 반환한다. 
BiFunctionT,
 U,
 R T와
 U
 타입을
 인자로
 받고
 R
 타입을
 반환한다. 
UnaryOperatorT T
 타입에
 적용되는
 단항
 연산자다. 
BinaryOperatorT T
 타입에
 적용되는
 이항
 연산자다.
신뢰할 수 없는 반환값 
ListContact contacts = ContactSource.findAll(); 
! 
Contact contact = contacts.stream() 
.filter(c - Florida.equals(c.getState())) 
.findFirst(); 
! 
contact.call(); 
스트림에서 필터 연산 후 
연락처(Contact) 객체를 찾아줘-
신뢰할 수 없는 반환값 
ListContact contacts = ContactSource.findAll(); 
! 
Contact contact = contacts.stream() 
.filter(c - Florida.equals(c.getState())) 
.findFirst(); 
! 
contact.call(); 
contact == null이면…? 
NullPointerException이 발생!
신뢰할 수 없는 반환값 
ListContact contacts = ContactSource.findAll(); 
! 
Contact contact = contacts.stream() 
.filter(c - Florida.equals(c.getState())) 
.findFirst(); 
! 
contact.call(); 
! 
if (contact != null) { 
contact.call(); 
} 방어코드로 회피…
신뢰할 수 있는 반환값 
java.util.OptionalT 
✔ Java 8에서 새롭게 추가된 클래스 
✔ 연산 후 반환값이 있을 수도 없을 수도 있을 때 사용 
✔ 반환값이 객체 또는 null인 T 보다 안전한 대안
신뢰할 수 있는 반환값 
java.util.OptionalT 
ListContact contacts = ContactSource.findAll(); 
! 
OptionalContact optional = contacts 
.stream() 
.filter(c - Florida.equals(c.getState())) 
.findFirst(); 
! 
! 
if (optional.isPresent()) { 
optional.get().call(); 
} 
값이 있으면 참(true)을 
값이 없으면 거짓(false)을 반환
신뢰할 수 있는 반환값 
java.util.OptionalT 
ListContact contacts = ContactSource.findAll(); 
! 
OptionalContact optional = contacts 
.stream() 
.filter(c - Florida.equals(c.getState())) 
.findFirst(); 
! 
! 
if (optional.isPresent()) { 
optional.get().call(); 
} 
반환값이 없을 수도 있어, 
그러니 꼭 확인해봐-!
신뢰할 수 있는 반환값 
java.util.OptionalT 
ListContact contacts = ContactSource.findAll(); 
! 
contacts.stream() 
.filter(contact - Florida.equals(c.getState())) 
.findFirst() 
.ifPresent(contact - contact.call()); 
값이 있으면 넘겨준 람다를 실행해줘-
신뢰할 수 있는 반환값 
java.util.OptionalT 
ListContact contacts = ContactSource.findAll(); 
! 
contacts.stream() 
.filter(contact - Florida.equals(c.getState())) 
.findFirst() 
.ifPresent(contact - contact.call()); 
! 
Contact findFirst = contacts.stream() 
.filter(Florida.equals(c.getState())) 
.findFirst() 
.orElseGet(() - Contact.empty()); 
값이 있으면 정상 값을 반환하고, 
없으면 기본 값을 반환해줘!
분할 반복자 인터페이스: Spliterator interface 
java.util.SpliteratorT 
✔ 스트림 API에 사용되는 새로운 클래스 
✔ 병렬 실행시 컬렉션의 데이터 요소를 분할 처리 
ListInteger numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); 
SpliteratorInteger firstSplit = numbers.spliterator(); 
SpliteratorInteger secondSplit = firstSplit.trySplit(); 
// firstSplit = 5, 6, 7, 8 
// secondSplit = 1, 2, 3, 4
스트림 API의 3단계 
orders.stream().map(n-n.price).sum(); 
스트림 생성 중개 연산 
(스트림 변환) 
최종 연산 
(스트림 사용)
스트림 API의 3단계 
orders.stream().map(n-n.price).sum(); 
스트림 생성 중개 연산 
(스트림 변환) 
최종 연산 
(스트림 사용)
스트림 API의 3단계 
1단계: 스트림 생성 
✔ Collection streams(), parallelStream() 
✔ Arrays streams(*) 
✔ Stream ranges range(...), rangeClosed(...) 
✔ Directly from values of(*) 
✔ Generators iterate(...), generate(...) 
✔ Resources lines()
스트림 API의 3단계 
1단계: 스트림 생성 
// 컬렉션(List)으로 순차 스트림 생성 
ListString collection = new ArrayList(); 
StreamString stream = collection.stream(); 
! 
// 배열을 스트림으로 변환 
IntStream stream = Arrays.stream(numbers); 
// of 메소드는 가변인자로 스트림을 생성 가능 
StreamString stream = Stream.of(Using, Stream, API, From, Java8); 
! 
// 1부터 10까지 유한 스트림 생성 
LongStream longStream = LongStream.rangeClosed(1, 10);
스트림 API의 3단계 
1단계: 스트림 생성 
// 컬렉션(List)으로 순차 스트림 생성 
ListString collection = new ArrayList(); 
StreamString stream = collection.stream(); 
! 
순차 스트림 생성 
// 배열을 스트림으로 변환 
IntStream stream = Arrays.stream(numbers); 
// of 메소드는 가변인자로 스트림을 생성 가능 
StreamString stream = Stream.of(Using, Stream, API, From, Java8); 
! 
// 1부터 10까지 유한 스트림 생성 
LongStream longStream = LongStream.rangeClosed(1, 10);
스트림 API의 3단계 
orders.stream().map(n-n.price).sum(); 
스트림 생성 중개 연산 
(스트림 변환) 
최종 연산 
(스트림 사용)
스트림 API의 3단계 
2단계: 중개 연산자: Intermediate Operator 
✔ 스트림을 받아서 스트림을 반환 
✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 
✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화)
스트림 API의 3단계 
2단계: 중개 연산자: Intermediate Operator 
✔ 스트림을 받아서 스트림을 반환 
✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 
✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화) 
contacts.stream() 
.filter(c - Florida.equals(c.getState())) 
.filter(c - Gender.Male == c.getGender()) 
.mapToInt(c - c.getAge()); 
최종 연산자 실행 전에는 내가 바로 중개 연산자! 
연산 처리하지 않는다
스트림 API의 3단계 
2단계: 중개 연산자: Intermediate Operator 
✔ 스트림을 받아서 스트림을 반환 
✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 
✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화) 
contacts.stream() 
.filter(c - Florida.equals(c.getState())) 
.filter(c - Gender.Male == c.getGender()) 
.mapToInt(c - c.getAge()); 
! 
for(Contact contact : contacts) { 
filter(…); 
filter(…); 
mapToInt(…); . 
} 
연산자 별로 처리를 하지 않고, 
모든 연산은 한번에 처리
스트림 API의 3단계 
orders.stream().map(n-n.price).sum(); 
스트림 생성 중개 연산 
(스트림 변환) 
최종 연산 
(스트림 사용)
스트림 API의 3단계 
3단계: 최종 연산자: Terminal operator 
✔ 스트림의 요소들을 연산 후 결과 값을 반환 
✔ 최종 연산 시 모든 연산 수행 (반복 작업 최소화) 
✔ 이후 더 이상 스트림을 사용할 수 없음 
contacts.stream() 
.filter(c - Florida.equals(c.getAddress().getState())) 
.filter(c - Gender.Male == c.getGender()) 
.mapToInt(c - c.getAge()) 
.average(); 
평균 값을 계산 후 반환하는 최종 연산자
지금까지 맛보기였습니다.
스트림 API 활용편
“스트림 API” 
활용편 
1. 뉴욕 주로 등록된 연락처만 출력 
2. 연락처에서 이메일만 출력 
3. 1부터 100까지 합계 구하기 
4. 사람들의 나이 합계, 평균, 최소, 최대 구하기 
5. 연락처에서 도시 목록 구하기 
6. 주 별로 연락처를 분류하기
[경고] 코드 여러 번 등장 
정신줄 꽉 붙잡으셔야 합니다.
뉴욕 주로 등록된 연락처만 출력 
ListContact 
contacts 
= 
ContactSource.findAll(); 
// 
for 
구문 
for(Contact 
contact 
: 
contacts) 
{ 
if(contact.equalToState(New 
York)) 
{ 
System.out.print(contact); 
} 
}
뉴욕 주로 등록된 연락처만 출력 
ListContact 
contacts 
= 
ContactSource.findAll(); 
// 
for 
구문 
for(Contact 
contact 
: 
contacts) 
{ 
if(contact.equalToState(New 
York)) 
{ 
System.out.print(contact); 
} 
} 
class Contact { 
public boolean equalToState(String state) { 
return Objects.equals(state, getState()); 
} 
}
조건을 만족하는 요소로 구성된 스트림을 얻을 때 
중개 연산: StreamT filter(T - boolean) 
✔ 각 요소를 확인해서 조건을 통과한 요소만으로 새 스트림 생성 
✔ 참/거짓을 반환하는 조건식을 인수로 전달 
T T T T T T n 
filter(T - boolean) 
T T T T
뉴욕 주로 등록된 연락처만 출력 
ListContact 
contacts 
= 
ContactSource.findAll(); 
// 
for 
구문 
for(Contact 
contact 
: 
contacts) 
{ 
if(contact.equalToState(New 
York)) 
{ 
System.out.print(contact); 
} 
} 
// 
Stream 
API(filter) 
+ 
Lambda 
Expressions 
contacts.stream() 
.filter(contact 
-­‐ 
contact.equalToState(New 
York))
각 요소별로 어떤 처리를 하고 싶을 때 
최종 연산: void forEach(T - void) 
✔ 각 요소를 인수로 전달된 함수에 전달해 처리 
✔ 최종 연산이기 때문이 이후 스트림을 사용할 수 없음 
T T T T T T n 
forEach(T - void)
뉴욕 주로 등록된 연락처만 출력 
ListContact 
contacts 
= 
ContactSource.findAll(); 
// 
for 
구문 
for(Contact 
contact 
: 
contacts) 
{ 
if(contact.equalToState(New 
York)) 
{ 
System.out.print(contact); 
} 
} 
// 
Stream 
API(filter, 
forEach) 
+ 
Lambda 
Expressions 
contacts.stream() 
.filter(contact 
-­‐ 
contact.equalToState(New 
York)) 
.forEach(contact 
-­‐ 
System.out.println(contact));

More Related Content

What's hot

Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API07.pallav
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive SpringKnoldus Inc.
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with SpringJoshua Long
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutinesNAVER Engineering
 
All you need to know about JavaScript loading and execution in the browser - ...
All you need to know about JavaScript loading and execution in the browser - ...All you need to know about JavaScript loading and execution in the browser - ...
All you need to know about JavaScript loading and execution in the browser - ...Caelum
 
Angular and The Case for RxJS
Angular and The Case for RxJSAngular and The Case for RxJS
Angular and The Case for RxJSSandi Barr
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introductionRasheed Waraich
 
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and KafkaEvent Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and KafkaVMware Tanzu
 
Karate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingKarate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingRoman Liubun
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type PatternsSimon Ritter
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolvedtrxcllnt
 
Java 8 - collections et stream
Java 8 - collections et streamJava 8 - collections et stream
Java 8 - collections et streamFranck SIMON
 

What's hot (20)

Java 8 Lambda and Streams
Java 8 Lambda and StreamsJava 8 Lambda and Streams
Java 8 Lambda and Streams
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
Java 8 streams
Java 8 streamsJava 8 streams
Java 8 streams
 
Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API
 
Ajax ppt
Ajax pptAjax ppt
Ajax ppt
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring
 
Lazy java
Lazy javaLazy java
Lazy java
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
react redux.pdf
react redux.pdfreact redux.pdf
react redux.pdf
 
Spring Boot Tutorial
Spring Boot TutorialSpring Boot Tutorial
Spring Boot Tutorial
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutines
 
All you need to know about JavaScript loading and execution in the browser - ...
All you need to know about JavaScript loading and execution in the browser - ...All you need to know about JavaScript loading and execution in the browser - ...
All you need to know about JavaScript loading and execution in the browser - ...
 
Angular and The Case for RxJS
Angular and The Case for RxJSAngular and The Case for RxJS
Angular and The Case for RxJS
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and KafkaEvent Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
 
Karate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingKarate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testing
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type Patterns
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
 
Java 8 - collections et stream
Java 8 - collections et streamJava 8 - collections et stream
Java 8 - collections et stream
 

Viewers also liked

자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개beom kyun choi
 
Spring framework 4.x
Spring framework 4.xSpring framework 4.x
Spring framework 4.xArawn Park
 
자바 8 스트림 API
자바 8 스트림 API자바 8 스트림 API
자바 8 스트림 APINAVER Corp
 
1. introduction to java8
1. introduction to java81. introduction to java8
1. introduction to java8흥래 김
 
Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기rupert kim
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개beom kyun choi
 
Resource Handling in Spring MVC
Resource Handling in Spring MVCResource Handling in Spring MVC
Resource Handling in Spring MVCArawn Park
 
[Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아![Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아!Arawn Park
 
Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기Arawn Park
 
Java 8 Streams & Collectors : the Leuven edition
Java 8 Streams & Collectors : the Leuven editionJava 8 Streams & Collectors : the Leuven edition
Java 8 Streams & Collectors : the Leuven editionJosé Paumard
 
Java 자료구조 비교 (Java1.6 기준)
Java 자료구조 비교 (Java1.6 기준)Java 자료구조 비교 (Java1.6 기준)
Java 자료구조 비교 (Java1.6 기준)혜웅 박
 
Gradle 사용하기
Gradle 사용하기Gradle 사용하기
Gradle 사용하기jiseob kim
 
20130709 gradle
20130709 gradle20130709 gradle
20130709 gradleSukjin Yun
 
Reactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OReactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OArawn Park
 
Twitter Api 번역계획서
Twitter Api 번역계획서Twitter Api 번역계획서
Twitter Api 번역계획서Jinho Jung
 
overview of spring4
overview of spring4overview of spring4
overview of spring4Arawn Park
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선daewon jeong
 
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )Arawn Park
 

Viewers also liked (20)

자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
Spring framework 4.x
Spring framework 4.xSpring framework 4.x
Spring framework 4.x
 
자바 8 스트림 API
자바 8 스트림 API자바 8 스트림 API
자바 8 스트림 API
 
1. introduction to java8
1. introduction to java81. introduction to java8
1. introduction to java8
 
Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개
 
Resource Handling in Spring MVC
Resource Handling in Spring MVCResource Handling in Spring MVC
Resource Handling in Spring MVC
 
[Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아![Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아!
 
Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기
 
Java 8 Streams & Collectors : the Leuven edition
Java 8 Streams & Collectors : the Leuven editionJava 8 Streams & Collectors : the Leuven edition
Java 8 Streams & Collectors : the Leuven edition
 
Gradle guide
Gradle guideGradle guide
Gradle guide
 
Java 자료구조 비교 (Java1.6 기준)
Java 자료구조 비교 (Java1.6 기준)Java 자료구조 비교 (Java1.6 기준)
Java 자료구조 비교 (Java1.6 기준)
 
Gradle 사용하기
Gradle 사용하기Gradle 사용하기
Gradle 사용하기
 
20130709 gradle
20130709 gradle20130709 gradle
20130709 gradle
 
Reactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OReactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/O
 
Twitter Api 번역계획서
Twitter Api 번역계획서Twitter Api 번역계획서
Twitter Api 번역계획서
 
overview of spring4
overview of spring4overview of spring4
overview of spring4
 
3. stream api
3. stream api3. stream api
3. stream api
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
 

Similar to 씹고 뜯고 맛보고 즐기는 스트림 API

2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)JiandSon
 
[Swift] Functions
[Swift] Functions[Swift] Functions
[Swift] FunctionsBill Kim
 
Linq to object using c#
Linq to object using c#Linq to object using c#
Linq to object using c#병걸 윤
 
파이썬정리 20160130
파이썬정리 20160130파이썬정리 20160130
파이썬정리 20160130Yong Joon Moon
 
Ksug 세미나 (윤성준) (20121208)
Ksug 세미나 (윤성준) (20121208)Ksug 세미나 (윤성준) (20121208)
Ksug 세미나 (윤성준) (20121208)Sungjoon Yoon
 
자바8강의 2강. Stream API
자바8강의 2강. Stream API자바8강의 2강. Stream API
자바8강의 2강. Stream APISejong Park
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++KWANGIL KIM
 
C++ 타입 추론
C++ 타입 추론C++ 타입 추론
C++ 타입 추론Huey Park
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crowJaeseung Ha
 
Java8 & Lambda
Java8 & LambdaJava8 & Lambda
Java8 & Lambda기현 황
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)JiandSon
 
Java jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_streamJava jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_stream성 남궁
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로Jaeseung Ha
 

Similar to 씹고 뜯고 맛보고 즐기는 스트림 API (20)

2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
 
Java stream v0.1
Java stream v0.1Java stream v0.1
Java stream v0.1
 
Java stream v0.1
Java stream v0.1Java stream v0.1
Java stream v0.1
 
[Swift] Functions
[Swift] Functions[Swift] Functions
[Swift] Functions
 
Linq to object using c#
Linq to object using c#Linq to object using c#
Linq to object using c#
 
파이썬정리 20160130
파이썬정리 20160130파이썬정리 20160130
파이썬정리 20160130
 
Ksug 세미나 (윤성준) (20121208)
Ksug 세미나 (윤성준) (20121208)Ksug 세미나 (윤성준) (20121208)
Ksug 세미나 (윤성준) (20121208)
 
자바8강의 2강. Stream API
자바8강의 2강. Stream API자바8강의 2강. Stream API
자바8강의 2강. Stream API
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++
 
GraphQL 적용기
GraphQL 적용기GraphQL 적용기
GraphQL 적용기
 
강의자료 2
강의자료 2강의자료 2
강의자료 2
 
C++ 타입 추론
C++ 타입 추론C++ 타입 추론
C++ 타입 추론
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crow
 
C review
C  reviewC  review
C review
 
Java8 & Lambda
Java8 & LambdaJava8 & Lambda
Java8 & Lambda
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
 
Java jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_streamJava jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_stream
 
6 function
6 function6 function
6 function
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
 

More from Arawn Park

우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?Arawn Park
 
코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우Arawn Park
 
kotlinx.serialization
kotlinx.serializationkotlinx.serialization
kotlinx.serializationArawn Park
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스Arawn Park
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다Arawn Park
 
점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정Arawn Park
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정Arawn Park
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to KotlinArawn Park
 
Spring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trendsSpring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trendsArawn Park
 

More from Arawn Park (10)

우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?
 
코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우
 
kotlinx.serialization
kotlinx.serializationkotlinx.serialization
kotlinx.serialization
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
 
점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to Kotlin
 
Spring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trendsSpring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trends
 

씹고 뜯고 맛보고 즐기는 스트림 API

  • 1. 씹고 뜯고 맛보고 즐기는 스트림 API KSUG & 지앤선이 함께하는 테크니컬 세미나 - KSUG에게 듣는 자바 8 이야기
  • 2. 박용권 KSUG 일꾼단 : 한국 스프링 사용자 모임(KSUG) : 봄싹(SpringSprout) : 라 스칼라 코딩단 http://about.me/arawn : twitter / @arawnkr
  • 3. 내 연락처에 등록된 사람들 중 플로리다에 사는 남자들의 평균 나이는?
  • 4. 명시적 반복을 통해 요구사항 구현… List<Contact> contacts = ContactSource.findAll(); int manCount = 0; int totalAge = 0; for(Contact contact : contacts) { if("Florida".equals(contact.getState()) && Gender.Male == contact.getGender()) { manCount += 1; totalAge += contact.getAge(); } } double averageAge = totalAge / manCount;
  • 5. 명시적 반복을 통해 요구사항 구현… List<Contact> contacts = ContactSource.findAll(); int manCount = 0; int totalAge = 0; for(Contact contact : contacts) { if("Florida".equals(contact.getState()) && Gender.Male == contact.getGender()) { manCount += 1; totalAge += contact.getAge(); 명령형 프로그래밍 } } double averageAge = totalAge / manCount;
  • 6. 명시적 반복을 통해 요구사항 구현… List<Contact> contacts = ContactSource.findAll(); int manCount = 0; int totalAge = 0; for(Contact contact : contacts) { if("Florida".equals(contact.getState()) && Gender.Male == contact.getGender()) { manCount += 1; totalAge += contact.getAge(); } } ! double averageAge = totalAge / manCount; 어떻게가 아닌, 무엇을 계산하는지가 중요
  • 7. 스트림 API와 람다 표현식으로 요구사항 구현… List<Contact> contacts = ContactSource.findAll(); contacts.stream() .filter(c -> "Florida".equals(c.getState())) .filter(c -> Gender.Male == c.getGender()) .mapToInt(c -> c.getAge()) .average();
  • 8. 스트림 API와 람다 표현식으로 요구사항 구현… List<Contact> contacts = ContactSource.findAll(); contacts.stream() .filter(c -> "Florida".equals(c.getState())) .filter(c -> Gender.Male == c.getGender()) .mapToInt(c -> c.getAge()) .average(); 파이프-필터 기반 API
  • 9. 결과 스트림 API의 처리 흐름 리듀스 (연산) 필터 (연산) 맵 소스 (연산)
  • 10. 스트림과 콜렉션은 다르다 Collection Stream contacts.forEach(c -> { ... }) ✔ 외부 반복(External Iteration) ✔ 반복을 통해 생성 ✔ 효율적이고 직접적인 요소 처리 ✔ 유한 데이터 구조 ✔ 반복적 재사용 가능 ✔ 내부 반복(Internal Iteration) ✔ 반복을 통해 연산 ✔ 파이프-필터 기반 API ✔ 무한 연속 흐름 데이터 구조 ✔ 재사용 불가 for(Contact c : contacts) { ... }
  • 12. 스트림 API의 목적 데이터 보관이 아닌 데이터 처리에 집중
  • 13. 스트림 API의 특징 반복의 내재화 ✔ 반복 구조 캡슐화(제어 흐름 추상화, 제어의 역전) ✔ 최적화와 알고리듬 분리 지연 연산 ✔ 스트림을 반환하는 필터-맵 API는 기본적으로 지연(lazy) 연산 ✔ 지연 연산을 통한 성능 최적화(무상태 중개 연산 및 반복 작업 최소화) 병렬 처리 ✔ 동일한 코드로 순차 또는 병렬 연산을 쉽게 처리 ✔ 쓰레드에 안전하지 않은 컬렉션도 병렬처리 지원 ✔ 단, 스트림 연산 중 데이터 원본을 변경하면 안된다
  • 14. 스트림 인터페이스: Stream interface java.util.stream Stream<T> IntStream LongStream DoubleStream
  • 15. 스트림 인터페이스: Stream interface Stream<T> IntStream LongStream DoubleStream ✔ 객체를 요소로 하는 범용 스트림 ✔ int를 요소로 하는 스트림 ✔ long을 요소로 하는 스트림 ✔ double을 요소로하는 스트림
  • 16. 스트림 인터페이스: Stream interface Stream<T> IntStream LongStream DoubleStream ✔ 객체를 요소로 하는 범용 스트림 ✔ int를 요소로 하는 스트림 ✔ long을 요소로 하는 스트림 ✔ double을 요소로하는 스트림
  • 17. 2가지 유형의 스트림 인터페이스 순차 스트림 (Sequential Stream) stream.parallel() stream.sequential() 병렬 스트림 (Parallel Stream)
  • 18. 함수형 인터페이스: Functional interfaces java.util.function.* ✔ 스트림 연산자의 대부분은 인수로 함수형 인터페이스를 받음 ✔ 함수형 인터페이스는 람다 표현식 또는 메소드 표현식으로 사용 함수형
  • 27.  U
  • 48.  R
  • 52.  R T
  • 56.  R
  • 59.  U,
  • 61.  U
  • 65.  R
  • 76. 신뢰할 수 없는 반환값 ListContact contacts = ContactSource.findAll(); ! Contact contact = contacts.stream() .filter(c - Florida.equals(c.getState())) .findFirst(); ! contact.call(); 스트림에서 필터 연산 후 연락처(Contact) 객체를 찾아줘-
  • 77. 신뢰할 수 없는 반환값 ListContact contacts = ContactSource.findAll(); ! Contact contact = contacts.stream() .filter(c - Florida.equals(c.getState())) .findFirst(); ! contact.call(); contact == null이면…? NullPointerException이 발생!
  • 78. 신뢰할 수 없는 반환값 ListContact contacts = ContactSource.findAll(); ! Contact contact = contacts.stream() .filter(c - Florida.equals(c.getState())) .findFirst(); ! contact.call(); ! if (contact != null) { contact.call(); } 방어코드로 회피…
  • 79. 신뢰할 수 있는 반환값 java.util.OptionalT ✔ Java 8에서 새롭게 추가된 클래스 ✔ 연산 후 반환값이 있을 수도 없을 수도 있을 때 사용 ✔ 반환값이 객체 또는 null인 T 보다 안전한 대안
  • 80. 신뢰할 수 있는 반환값 java.util.OptionalT ListContact contacts = ContactSource.findAll(); ! OptionalContact optional = contacts .stream() .filter(c - Florida.equals(c.getState())) .findFirst(); ! ! if (optional.isPresent()) { optional.get().call(); } 값이 있으면 참(true)을 값이 없으면 거짓(false)을 반환
  • 81. 신뢰할 수 있는 반환값 java.util.OptionalT ListContact contacts = ContactSource.findAll(); ! OptionalContact optional = contacts .stream() .filter(c - Florida.equals(c.getState())) .findFirst(); ! ! if (optional.isPresent()) { optional.get().call(); } 반환값이 없을 수도 있어, 그러니 꼭 확인해봐-!
  • 82. 신뢰할 수 있는 반환값 java.util.OptionalT ListContact contacts = ContactSource.findAll(); ! contacts.stream() .filter(contact - Florida.equals(c.getState())) .findFirst() .ifPresent(contact - contact.call()); 값이 있으면 넘겨준 람다를 실행해줘-
  • 83. 신뢰할 수 있는 반환값 java.util.OptionalT ListContact contacts = ContactSource.findAll(); ! contacts.stream() .filter(contact - Florida.equals(c.getState())) .findFirst() .ifPresent(contact - contact.call()); ! Contact findFirst = contacts.stream() .filter(Florida.equals(c.getState())) .findFirst() .orElseGet(() - Contact.empty()); 값이 있으면 정상 값을 반환하고, 없으면 기본 값을 반환해줘!
  • 84. 분할 반복자 인터페이스: Spliterator interface java.util.SpliteratorT ✔ 스트림 API에 사용되는 새로운 클래스 ✔ 병렬 실행시 컬렉션의 데이터 요소를 분할 처리 ListInteger numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); SpliteratorInteger firstSplit = numbers.spliterator(); SpliteratorInteger secondSplit = firstSplit.trySplit(); // firstSplit = 5, 6, 7, 8 // secondSplit = 1, 2, 3, 4
  • 85. 스트림 API의 3단계 orders.stream().map(n-n.price).sum(); 스트림 생성 중개 연산 (스트림 변환) 최종 연산 (스트림 사용)
  • 86. 스트림 API의 3단계 orders.stream().map(n-n.price).sum(); 스트림 생성 중개 연산 (스트림 변환) 최종 연산 (스트림 사용)
  • 87. 스트림 API의 3단계 1단계: 스트림 생성 ✔ Collection streams(), parallelStream() ✔ Arrays streams(*) ✔ Stream ranges range(...), rangeClosed(...) ✔ Directly from values of(*) ✔ Generators iterate(...), generate(...) ✔ Resources lines()
  • 88. 스트림 API의 3단계 1단계: 스트림 생성 // 컬렉션(List)으로 순차 스트림 생성 ListString collection = new ArrayList(); StreamString stream = collection.stream(); ! // 배열을 스트림으로 변환 IntStream stream = Arrays.stream(numbers); // of 메소드는 가변인자로 스트림을 생성 가능 StreamString stream = Stream.of(Using, Stream, API, From, Java8); ! // 1부터 10까지 유한 스트림 생성 LongStream longStream = LongStream.rangeClosed(1, 10);
  • 89. 스트림 API의 3단계 1단계: 스트림 생성 // 컬렉션(List)으로 순차 스트림 생성 ListString collection = new ArrayList(); StreamString stream = collection.stream(); ! 순차 스트림 생성 // 배열을 스트림으로 변환 IntStream stream = Arrays.stream(numbers); // of 메소드는 가변인자로 스트림을 생성 가능 StreamString stream = Stream.of(Using, Stream, API, From, Java8); ! // 1부터 10까지 유한 스트림 생성 LongStream longStream = LongStream.rangeClosed(1, 10);
  • 90. 스트림 API의 3단계 orders.stream().map(n-n.price).sum(); 스트림 생성 중개 연산 (스트림 변환) 최종 연산 (스트림 사용)
  • 91. 스트림 API의 3단계 2단계: 중개 연산자: Intermediate Operator ✔ 스트림을 받아서 스트림을 반환 ✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 ✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화)
  • 92. 스트림 API의 3단계 2단계: 중개 연산자: Intermediate Operator ✔ 스트림을 받아서 스트림을 반환 ✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 ✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화) contacts.stream() .filter(c - Florida.equals(c.getState())) .filter(c - Gender.Male == c.getGender()) .mapToInt(c - c.getAge()); 최종 연산자 실행 전에는 내가 바로 중개 연산자! 연산 처리하지 않는다
  • 93. 스트림 API의 3단계 2단계: 중개 연산자: Intermediate Operator ✔ 스트림을 받아서 스트림을 반환 ✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 ✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화) contacts.stream() .filter(c - Florida.equals(c.getState())) .filter(c - Gender.Male == c.getGender()) .mapToInt(c - c.getAge()); ! for(Contact contact : contacts) { filter(…); filter(…); mapToInt(…); . } 연산자 별로 처리를 하지 않고, 모든 연산은 한번에 처리
  • 94. 스트림 API의 3단계 orders.stream().map(n-n.price).sum(); 스트림 생성 중개 연산 (스트림 변환) 최종 연산 (스트림 사용)
  • 95. 스트림 API의 3단계 3단계: 최종 연산자: Terminal operator ✔ 스트림의 요소들을 연산 후 결과 값을 반환 ✔ 최종 연산 시 모든 연산 수행 (반복 작업 최소화) ✔ 이후 더 이상 스트림을 사용할 수 없음 contacts.stream() .filter(c - Florida.equals(c.getAddress().getState())) .filter(c - Gender.Male == c.getGender()) .mapToInt(c - c.getAge()) .average(); 평균 값을 계산 후 반환하는 최종 연산자
  • 98. “스트림 API” 활용편 1. 뉴욕 주로 등록된 연락처만 출력 2. 연락처에서 이메일만 출력 3. 1부터 100까지 합계 구하기 4. 사람들의 나이 합계, 평균, 최소, 최대 구하기 5. 연락처에서 도시 목록 구하기 6. 주 별로 연락처를 분류하기
  • 99. [경고] 코드 여러 번 등장 정신줄 꽉 붙잡으셔야 합니다.
  • 100. 뉴욕 주로 등록된 연락처만 출력 ListContact contacts = ContactSource.findAll(); // for 구문 for(Contact contact : contacts) { if(contact.equalToState(New York)) { System.out.print(contact); } }
  • 101. 뉴욕 주로 등록된 연락처만 출력 ListContact contacts = ContactSource.findAll(); // for 구문 for(Contact contact : contacts) { if(contact.equalToState(New York)) { System.out.print(contact); } } class Contact { public boolean equalToState(String state) { return Objects.equals(state, getState()); } }
  • 102. 조건을 만족하는 요소로 구성된 스트림을 얻을 때 중개 연산: StreamT filter(T - boolean) ✔ 각 요소를 확인해서 조건을 통과한 요소만으로 새 스트림 생성 ✔ 참/거짓을 반환하는 조건식을 인수로 전달 T T T T T T n filter(T - boolean) T T T T
  • 103. 뉴욕 주로 등록된 연락처만 출력 ListContact contacts = ContactSource.findAll(); // for 구문 for(Contact contact : contacts) { if(contact.equalToState(New York)) { System.out.print(contact); } } // Stream API(filter) + Lambda Expressions contacts.stream() .filter(contact -­‐ contact.equalToState(New York))
  • 104. 각 요소별로 어떤 처리를 하고 싶을 때 최종 연산: void forEach(T - void) ✔ 각 요소를 인수로 전달된 함수에 전달해 처리 ✔ 최종 연산이기 때문이 이후 스트림을 사용할 수 없음 T T T T T T n forEach(T - void)
  • 105. 뉴욕 주로 등록된 연락처만 출력 ListContact contacts = ContactSource.findAll(); // for 구문 for(Contact contact : contacts) { if(contact.equalToState(New York)) { System.out.print(contact); } } // Stream API(filter, forEach) + Lambda Expressions contacts.stream() .filter(contact -­‐ contact.equalToState(New York)) .forEach(contact -­‐ System.out.println(contact));
  • 106. 연락처에서 이메일만 출력 ListContact contacts = ContactsSource.contacts(); // for 구문 for(Contact contact : contacts) { System.out.println(contact.getEmail()); }
  • 107. 연락처에서 이메일만 출력 ListContact contacts = ContactsSource.contacts(); // for 구문 for(Contact contact : contacts) { System.out.println(contact.getEmail()); } ! // Stream API + Lambda Expressions contacts.stream() .forEach(contact -­‐ System.out.println(contact.getEmail()));
  • 108. 스트림에 있는 값들을 변환하고 싶을 때 중개 연산: StreamR map(T - R) ✔ T 타입의 요소를 1:1로 R 타입의 요소로 변환 후 스트림 생성 ✔ 변환을 처리하는 함수를 인수로 전달 T R T R T R T R T R T R n map(T - R)
  • 109. 연락처에서 이메일만 출력 ListContact contacts = ContactsSource.contacts(); // for 구문 for(Contact contact : contacts) { System.out.println(contact.getEmail()); } ! // Stream API + Lambda Expressions contacts.stream() .forEach(contact -­‐ System.out.println(contact.getEmail())); ! // Stream API + Lambda Expressions contacts.stream() .map(contact -­‐ contact.getEmail()) .forEach(email -­‐ System.out.println(email));
  • 110. 연락처에서 이메일만 출력 ListContact contacts = ContactsSource.contacts(); // for 구문 for(Contact contact : contacts) { System.out.println(contact.getEmail()); } ! // Stream API + Lambda Expressions contacts.stream() .forEach(contact -­‐ System.out.println(contact.getEmail())); ! // Stream API + Lambda Expressions contacts.stream() .map(contact -­‐ contact.getEmail()) .forEach(email -­‐ System.out.println(email)); // Stream API + Method References contacts.stream() .map(Contact::getEmail) .forEach(System.out::println); 메소드 참조: 람다 표현식의 다른 형태, class::method 로 사용
  • 111. 1부터 100까지 합계 구하기 // for 구문 int sum = 0; for(int number = 1; number = 100; number++) { sum += number; }
  • 112. 스트림의 값들을 결합 또는 계산하고 싶을 때 최종 연산: reduce ✔ OptionalT reduce((T, T) - T) ✔ T reduce(T, (T, T) - T) ✔ T 타입의 요소 둘 씩 reducer로 계산해 최종적으로 하나의 값을 계산
  • 113. 스트림의 값들을 결합 또는 계산하고 싶을 때 최종 연산: reduce 연산 흐름 T T T T T T T T n R
  • 114. 스트림의 값들을 결합 또는 계산하고 싶을 때 최종 연산: reduce 연산 흐름 T T T T T T T T n R T
  • 115. 스트림의 값들을 결합 또는 계산하고 싶을 때 최종 연산: reduce 연산 흐름 T T T T T T T T n T T R
  • 116. 스트림의 값들을 결합 또는 계산하고 싶을 때 최종 연산: reduce 연산 흐름 T T T T T T T T n T T T T T T T R
  • 117. 1부터 100까지 합계 구하기 // for 구문 int sum = 0; for(int number = 1; number = 100; number++) { sum += number; } // Stream API + Lambda Expressions int sum = IntStream.rangeClosed(1, 100) .reduce(0, (left, right) -­‐ left + right);
  • 118. 1부터 100까지 합계 구하기 (1 to 100).reduce((l, r) - l + r) 1 2 3 4 5 6 7 … 100 6 3 10 15 21 28 … 5050
  • 119. 1부터 100까지 합계 구하기 // for 구문 int sum = 0; for(int number = 1; number = 100; number++) { sum += number; } // Stream API + Lambda Expressions int sum = IntStream.rangeClosed(1, 100) .parallel() .reduce(0, (left, right) -­‐ left + right);
  • 120. 1부터 100까지 합계 구하기 병렬 스트림을 통한 reduce 연산 흐름 1 2 3 4 5 6 7 8 n
  • 121. 1부터 100까지 합계 구하기 병렬 스트림을 통한 reduce 연산 흐름 1 2 3 4 5 6 7 8 n 3 11
  • 122. 1부터 100까지 합계 구하기 병렬 스트림을 통한 reduce 연산 흐름 1 2 3 4 5 6 7 8 n 3 11 6 18 10 26
  • 123. 1부터 100까지 합계 구하기 병렬 스트림을 통한 reduce 연산 흐름 1 2 3 4 5 6 7 8 n 3 11 6 18 10 26 36 병렬 처리를 손 안대고 코풀듯이 할 수 있어요!
  • 124. 1부터 100까지 합계 구하기 // for 구문 int sum = 0; for(int number = 1; number = 100; number++) { sum += number; } // Stream API + Lambda Expressions int sum = IntStream.rangeClosed(1, 100) .reduce(0, (left, right) -­‐ left + right); // Stream API + Method References int sum = IntStream.rangeClosed(1, 100) .reduce(0, Integer::sum); 두 개의 수를 받아 합계를 계산하는 메소드- JDK에 구현되어 있는 다양한 메소드를 활용하면 좋아요!
  • 125. 사람들의 나이 합계, 평균, 최소, 최대 구하기 ListContact contacts = ContactSource.findAll(); long sum = 0; int min = 0, max = 0; for(Contact contact : contacts) { int age = contact.getAge(); sum += age; min = Math.min(min, age); max = Math.max(max, age); } double average = sum / contacts.size();
  • 126. 기본 타입 스트림이 제공하는 편리한 계산식 최종 연산: sum() | average() | min() | max() ✔ 합계 - [int, long, double] sum() ✔ 평균 - OptionalDouble average() ✔ 최소값 - Optional[Int, Long, Double] min() ✔ 최대값 - Optional[Int, Long, Double] max()
  • 127. 사람들의 나이 합계, 평균, 최소, 최대 구하기 ListContact contacts = ContactSource.findAll(); ! // for 구문 long sum = 0; int min = 0, max = 0; for(Contact contact : contacts) { int age = contact.getAge(); sum += age; min = Math.min(min, age); max = Math.max(max, age); 4번이나 반복하다니! } double average = sum / contacts.size(); ! // Stream API + Method References int sum = contacts.stream().mapToInt(Contact::getAge).sum(); OptionalDouble average = contacts.stream().mapToInt(Contact::getAge).average(); OptionalInt min = contacts.stream().mapToInt(Contact::getAge).min(); OptionalInt max = contacts.stream().mapToInt(Contact::getAge).max();
  • 128. 기본 타입 스트림이 제공하는 편리한 계산식 최종 연산: summaryStatistics() ✔ [Int, Long, Double]SummaryStatistics summaryStatistics() ✔ 합계, 평균, 최소값, 최대값, 개수에 대한 요약 통계
  • 129. 사람들의 나이 합계, 평균, 최소, 최대 구하기 ListContact contacts = ContactSource.findAll(); ! // Stream API + Method References IntSummaryStatistics summaryStatistics = contacts.stream() .mapToInt(Contact::getAge) .summaryStatistics(); !! long sum = summaryStatistics.getSum(); double average = summaryStatistics.getAverage(); int min = summaryStatistics.getMin(); int max = summaryStatistics.getMax(); long count = summaryStatistics.getCount();
  • 130. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // for 구문 ListString cities = new ArrayList(); for(Contact contact : contacts) { String city = contact.getCity(); cities.add(contact.getCity()); }
  • 131. 스트림 연산 후 결과를 살펴보고 싶을 때 최종 연산: 집계 ✔ iterator() ✔ Object[] toArray() ✔ A[] toArray(IntFunctionA[]) ✔ R collect(() - R, (R, T) - R, (R, R) - void) : () - R = 공급자, 대상 객체의 새로운 인스턴스 생성(ex, ArrayList 생성) : (R, T) - R = 누산자, 요소를 대상에 추가(ex, List.add(…)) : (R, R) - void = 결합자, 두 객체를 하나로 병합(ex, List.addAll(…)) ✔ R collect(CollectorT, ?, R)
  • 132. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // for 구문 ListString cities = new ArrayList(); for(Contact contact : contacts) { String city = contact.getCity(); cities.add(contact.getCity()); } ! // 반복자로 집계 IteratorContact contactIterator = contacts.stream().iterator(); // 배열로 집계 Object[] objectArray = contacts.stream().toArray(); Contact[] contactArray = contacts.stream().toArray(Contact[]::new);
  • 133. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // Stream API(collect(공급자, 누산자, 결합자)) + Lambda Expressions cities = contacts.stream() .map(contact - contact.getCity()) .collect( () - new ArrayList() , (list, city) - list.add(city) , (left, right) - left.addAll(right));
  • 134. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // Stream API(collect(공급자, 누산자, 결합자)) + Lambda Expressions cities = contacts.stream() .map(contact - contact.getCity()) .collect( () - new ArrayList() , (list, city) - list.add(city) , (left, right) - left.addAll(right)); // Stream API(collect(공급자, 누산자, 결합자)) + Method References cities = contacts.stream() .map(contact - contact.getCity()) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
  • 135. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // Stream API(collect(공급자, 누산자, 결합자)) + Lambda Expressions cities = contacts.stream() .map(contact - contact.getCity()) .collect( () - new ArrayList() , (list, city) - list.add(city) , (left, right) - left.addAll(right)); // Stream API(collect(공급자, 누산자, 결합자)) + Method References cities = contacts.stream() .map(contact - contact.getCity()) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); // Stream API(collect(Collector interface)) + Method References cities = contacts.stream() .map(contact - contact.getCity()) .collect(Collectors.toList());
  • 136. 연락처에서 도시 목록 구하기 ListContact contacts = ContactSource.findAll(); // Stream API(collect(공급자, 누산자, 결합자)) + Lambda Expressions cities = contacts.stream() .map(contact - contact.getCity()) .collect( () - new ArrayList() , (list, city) - list.add(city) , (left, right) - left.addAll(right)); // Stream API(collect(공급자, 누산자, 결합자)) + Method References cities = contacts.stream() .map(contact - contact.getCity()) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); // Stream API(collect(Collector interface)) + Method References cities = contacts.stream() .map(contact - contact.getCity()) .distinct() .collect(Collectors.toList()); 중복 제거
  • 137. 스트림 연산 후 결과를 살펴보고 싶을 때 Collectors: 공통 컬렉터용 팩토리 메소드를 제공 // Collection 타입으로 요소를 모을 때 contacts.stream().collect(Collectors.toList()); contacts.stream().collect(Collectors.toSet()); contacts.stream().collect(Collectors.toCollection(TreeSet::new)); // Map 타입으로 요소를 모을 때 contacts.stream().collect(Collectors.toMap( Contact::getName , Contact::getBirthday)); contacts.stream().collect(Collectors.toMap( Contact::getName , Function.identity())); // 스트림에 있는 모든 문자열을 서로 연결해서 모을 때 contacts.stream().map(Contact::getName).collect(Collectors.joining()); contacts.stream().map(Object::toString).collect(Collectors.joining(|));
  • 138. 주 별로 연락처를 분류하기 ListContact contacts = ContactSource.findAll(); // for 구문 MapString, ListContact contactsByState = new HashMap(); for(Contact contact : contacts) { if(!contactsByState.containsKey(contact.getState())) { contactsByState.put(contact.getState(), new ArrayList()); } contactsByState.get(contact.getState()).add(contact); }
  • 139. 주 별로 연락처를 분류하기 ListContact contacts = ContactSource.findAll(); // for 구문 MapString, ListContact contactsByState = new HashMap(); for(Contact contact : contacts) { if(!contactsByState.containsKey(contact.getState())) { contactsByState.put(contact.getState(), new ArrayList()); } contactsByState.get(contact.getState()).add(contact); } // // Stream API(collect(groupingBy)) + Method References contactsByState = contacts.stream() .collect(Collectors.groupingBy(Contact::getState));
  • 142. 스트림 API의 3단계 orders.stream().map(n-n.price).sum(); 스트림 생성 중개 연산 (스트림 변환) 최종 연산 (스트림 사용)
  • 143. 스트림 생성 ✔ Collection streams(), parallelStream() ✔ Arrays streams(*) ✔ Stream ranges range(...), rangeClosed(...) ✔ Directly from values of(*) ✔ Generators iterate(...), generate(...) ✔ Resources lines()
  • 144. 스트림 생성 Collection ListString collection = new ArrayList(); collection.add(김지영); collection.add(박성철); collection.add(박용권); collection.add(정대원); // 순차 스트림 StreamString stream = collection.stream(); // 병렬 스트림 StreamString parallelStream = collection.parallelStream();
  • 145. 스트림 생성 Arrays int[] numbers = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; // 배열을 스트림으로 변환 IntStream stream = Arrays.stream(numbers); // 순차 스트림을 병렬 스트림으로 변환 IntStream parallelStream = stream.parallel();
  • 146. 스트림 생성 Directly from values // of 메소드는 가변인자로 스트림을 생성 가능 StreamString stream = Stream.of(Using, Stream, API, From, Java8); // 순차 스트림을 병렬 스트림으로 변환 StreamString parallelStream = stream.parallel();
  • 147. 스트림 생성 Stream ranges // 1부터 9까지 유한 스트림 생성 IntStream intStream = IntStream.range(1, 10); // 1부터 10까지 유한 스트림 생성 LongStream longStream = LongStream.rangeClosed(1, 10);
  • 148. 스트림 생성 Generators: 무한 스트림(Infinite Stream) // 난수 스트림 StreamDouble random = Stream.generate(Math::random); // 0 1 2 3 ... 무한 수열 StreamInteger numbers = Stream.iterate(0, n - n + 1);
  • 149. 스트림 생성 Generators: 무한 스트림(Infinite Stream) // 난수 스트림 StreamDouble random = Stream.generate(Math::random); // 0 1 2 3 ... 무한 수열 StreamInteger numbers = Stream.iterate(0, n - n + 1); // 피보나치 수열 Streamint[] fibonacci = Stream.iterate( new int[]{0,1} , n - new int[]{n[1], n[0]+n[1]}); fibonacci.limit(10) .map(n - n[0]) .forEach(System.out::println);
  • 150. 스트림 생성 Resources // CSV 파일을 읽어 스트림을 생성 try(StreamString lines = Files.lines(Paths.get(addressBook.csv))) { long count = lines.map(line - line.split(,)) .filter(values - values[6].contains(FL)) .count(); } catch (IOException e) { throw new RuntimeException(e); }
  • 151. 스트림 연산자 중개 연산자: Intermediate Operator ✔ 스트림을 받아서 스트림을 반환 ✔ 무상태 연산과 내부 상태 유지 연산으로 나누어짐 ✔ 기본적으로 지연(lazy) 연산 처리(성능 최적화) 최종 연산자: Terminal operator ✔ 스트림을 받아서 최종 결과 값를 반환 ✔ 최종 연산 시 모든 연산 수행 (반복 작업 최소화) ✔ 이후 더이상 스트림을 사용할 수 없음
  • 152. 스트림 중개 연산자 무상태 연산 ✔ StreamT filter(Predicate? super T predicate) : T 타입의 요소를 확인해서 기준에 통과한 요소만으로 새 스트림 생성 ✔ StreamR map(Function? super T, ? extends R mapper) : T 타입의 요소를 1:1로 R 타입의 요소로 변환 후 스트림 생성 ✔ StreamR flatMap(FunctionT, Stream? extends R mapper) : T 타입의 요소를 1:n으로 R 타입의 요소로 변환 후 스트림 생성, Monad bind() ✔ StreamT skip(long n) : 처음 n개의 요소를 제외한 나머지 요소로 새 스트림 생성 ✔ StreamT limit(long n) : 처음 n개의 요소로 새 스트림 생성 ✔ StreamT peek(Consumer? super T action) : T 타입의 요소를 엿본 후 스트림 생성
  • 153. 스트림 중개 연산자 내부 상태 유지 연산 ✔ StreamT sorted() : 정렬된 스트림 생성, T 타입은 Comparable 인터페이스를 구현하고 있어야 함 ✔ StreamT sorted(Comparator? super T comparator) : 주어진 Comparator 객체를 사용해 정렬된 스트림 생성 ✔ StreamT distinct() : 중복된 요소를 제거한 스트림 생성
  • 154. 스트림 최종 연산자 범용 연산 I ✔ OptionalT reduce(BinaryOperatorT reducer)* : T 타입의 요소 둘 씩 reducer로 계산해 최종적으로 하나의 값을 계산 ✔ OptionalT min(Comparator? super T comparator) : T 타입의 요소 중 최소 값을 찾아 반환 ✔ OptionalT max(Comparator? super T comparator) : T 타입의 요소 중 최대 값을 찾아 반환 ✔ OptionalT findFirst() : 비어 있지 않은 스트림에서 첫 번째 값을 반환(filter 연산 결합시 유용) ✔ OptionalT findAny() : 첫 번째 값은 물론 어떤 요소든지 찾으면 반환(filter 연산 결합시 유용) ✔ long count() : 스트림에서 요소의 개수를 반환
  • 155. 스트림 최종 연산자 범용 연산 II ✔ boolean anyMatch(Predicate? super T predicate) : T 타입의 요소 중 조건을 만족하는 요소가 있는지 검사 ✔ boolean allMatch(Predicate? super T predicate) : T 타입의 모든 요소가 조건을 만족하는지 검사 ✔ boolean noneMatch(Predicate? super T predicate) : T 타입의 모든 요소가 조건을 만족하지 않는지 검사
  • 156. 스트림 최종 연산자 범용 연산 III ✔ R collect(Collector? super T, R collector) : T 타입의 요소를 모두 모아 하나의 자료구조나 값으로 변환 ✔ void forEach(Consumer? super T consumer) : T 타입의 요소를 하나씩 처리
  • 157. 스트림 최종 연산자 기본 타입 스트림 전용 연산 ✔ int|long|double sum() : 요소들의 합계를 반환 ✔ OptionalDouble average() : 요소들의 평균을 반환 ✔ OptionalInt|Long|Double min() : 최소값을 가진 요소를 반환 ✔ OptionalInt|Long|Double max() : 최대값을 가진 요소를 반환 ✔ Int|Long|DoubleSummaryStatistics summaryStatistics() : 요소들의 합계, 평균, 개수, 최소값, 최대값을 반환
  • 159. 요약 ✔ 스트림 라이브러리 : 컬렉션 프레임워크보다 한 단계 더 높은 추상화된 API : 내부 반복을 통해 제어 흐름 추상화하고 최적화와 알고리듬을 분리 ✔ 스트림 연산 : 중개 연산 / 파이프와 필터, 맵(Map) : 최종 연산 / 결과 생산(Reduce) ✔ 지연 연산을 통한 성능 최적화 ✔ 병렬 처리 추상화를 통한 손쉬운 사용 ✔ 컬렉션 외 다양한 연속적 데이터에 사용
  • 162. 참고자료 ✔ 가장 빨리 만나는 자바8 : http://www.gilbut.co.kr/book/bookView.aspx?bookcode=BN000898page=1TF=T ✔ 자바 8 람다의 이해와 의미 : http://www.slideshare.net/gyumee/java-8-lambda-35352385 ✔ Brand new Data Processing - Stream API : http://www.slideshare.net/bitter_fox/brand-newdataprocessing ✔ The Stream API : http://blog.hartveld.com/2013/03/jdk-8-33-stream-api.html ✔ java.util.stream (Java Platform SE 8) : http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html ✔ Lambdas and Streams in Java 8 Libraries : http://www.drdobbs.com/jvm/lambdas-and-streams-in-java-8-libraries/240166818