SlideShare a Scribd company logo
1 of 39
Download to read offline
Stream API
Javacafe 백엔드 스터디 (자바8)
목차
• 복습
• 데이터 수집하기
• 컬렉터 소개
• 리듀싱과 요약
• 그룹화 및 분할
• Collector 인터페이스와 구현
• 병렬스트림 사용하기
• 병렬 스트림 제대로 사용하기
List<Dish> lowCaloricDishes = new ArrayList<>();
// 칼로리가 400이하인 메뉴만 가지고 온다.
for (Dish d : menu) {
if (d.getCalories() < 400) {
lowCaloricDishes.add(d);
}
}
// 칼로리 순으로 정렬
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCalories(), o2.getCalories());
}
});
// 요리 이름만 가지고 온다.
List<String> lowCaloricDishesName = new ArrayList<>();
for (Dish d : lowCaloricDishes) {
lowCaloricDishesName.add(d.getName());
}
// 상위 3개의 결과만 반환한다
List<String> lowCaloricLimit3DisishesName = lowCaloricDishesName.subList(0, 3);
System.out.println(lowCaloricLimit3DisishesName);
클래식 자바 스타일, 컬렉션을 활용한 요구사항 구현
두번째 시간 복습
Stream API를 활용한다면!!
List<String> lowCaloricDishesName = menu.stream()
.filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
System.out.println(lowCaloricDishesName);
두번째 시간 복습
두번째 시간 복습
• 컬렉션과 스트림 모두 연속된 요소 형식의 값을 저장하는
자료형 인터페이스이다.
• 컬렉션은 자료를 저장하는데 특화되어있다.
스트림은 요소들을 연산하기 위한 자료형이다.
• 데이터 연산 방식에도 큰 차이가 있다.
– 컬렉션 : 연산 과정을 직접 작성하여 한다.
각 로직의 순서에 따라 연산이 순차적으로 진
행된다.
– 스트림 : 연산은 라이브러리가 알아서 진행한다.
ㄴㄴㄴㄴ종결연산 메서드에서 연산이 한꺼번에 진행
된다.
스트림 vs 컬렉션
filter map limit collect
중간연산 최종연산
menu.stream().filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
중간연산은 파이프라인으로 연결
되어 선언식이 최종연산으로 전달
된다.
중간연산 정보를 스트림으로 입력받
아 최종연산에서 한번에 처리한다.
단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다. (Lazy)
모든 중간연산을 합친 다음 최종연산에서 한번에 처리한다.
두번째 시간 복습
스트림 API
두번째 시간 복습
데이터 수집하기
요구사항
● 통화별로 트랜잭션을 그룹화한 다음에 해당 통화
의 모든 합계를 계산하시오.
Map<Currency, Integer> 형식 반환
● 트랜잭션을 나라별로 그룹화 한뒤. 각 트랜잭션의
5000이상일 경우를 구분하여 리스트로 반환하시
오.
Map<String, Map<Boolean, List<Transaction>>> 반
환
데이터 수집하기
요구사항 :
각 트랜잭션을 Currency로 분류하여 반환하여라.
Map<Currency, List<Transaction>>반환
Map<Currency, List<Transaction>> resultCurrencies = new HashMap<>();
for (Transaction transaction : transactions) {
Currency currency = transaction.getCurrency();
List<Transaction> transactionsForCurrency = resultCurrencies.get(currency);
if (transactionsForCurrency == null) {
transactionsForCurrency = new ArrayList<>();
resultCurrencies.put(currency, transactionsForCurrency);
}
transactionsForCurrency.add(transaction);
}
데이터 수집하기
요구사항 :
각 트랜잭션을 Currency로 묶은다음 반환하여라.
Map<Currency, List<>> transactionsByCurrencies =
transactions.stream()
.collect(groupingBy(Transaction::getCurrency));
데이터 수집하기 - 컬렉터 소개
● collect는 Stream 최종연산 메서드
● collect 종결연산 메서드 스트림의 결과를 수집
● 인자로 Collector<T, A, R>의 구현체를 받는다.
● Collector에서 결과값에 대한 연산작업이 정의
transactions.stream()
.collect(Collectors.groupingBy(Transaction::getCurrency));
데이터 수집하기 - 컬렉터 소개
데이터 수집하기 - 컬렉터 소개
미리 정의된 컬렉터 Collectors
자주 사용되는 Collector의 구현체를 제공하는 팩터리 메서드들의 집합 클
래스
● 스트림 요소를 하나의 값으로 리듀스 또는 요약
● 스트림 요소 그룹화
● 스트림 요소 분할
데이터 수집하기 - 리듀싱과 요약
각 요소의 값을 줄여가며, 하나의 결과값을 반환
각 요소들의 최댓값, 최솟값, 평균등의 값을 도출
데이터 수집하기 - 리듀싱과 요약
최댓값과 최솟값 검색하기
maxBy, minBy메서드를 사용하여 최댓값과 최솟값을 찾을 수 있다.
Comparator<Dish> dishCaloriesComparator =
Comparator.comparingInt(Dish::getCalories);
Dish mostCalorieDish = menu.stream()
.collect(Collectors.maxBy(dishCaloriesComparator))
.get();
Dish lowestCalorieDish = menu.stream()
.collect(Collectors.minBy(dishCaloriesComparator))
.get();
데이터 수집하기 - 리듀싱과 요약
요소의 합계 및 평균 구하기
summingInt, SummingLong, SummingDouble : 요소의 합 도출
averageInt, averageLong, averageDouble : 요소의 평균 도출
int totalCalories = Dish.menu.stream()
.collect(Collectors.summingInt(Dish::getCalories));
Double collect = Dish.menu.stream()
.collect(Collectors.averagingInt(Dish::getCalories));
데이터 수집하기 - 리듀싱과 요약
요약연산
summarizingInt로 요소의 합계, 평균, 최솟값, 최댓값의 정보를 한꺼번에
가져올 수 있다.
// count=9, sum=4300, min=120, average=477.777778, max=800
IntSummaryStatistics menuStatistics = Dish.menu.stream().
collect(
Collectors.summarizingInt(Dish::getCalories)
);
데이터 수집하기 - 리듀싱과 요약
문자열 연결
joining메서드를 사용하여 각 문자열 요소를 합쳐 결과로 반환할 수 있다.
//pork, beef, chicken ... pizza, prawns, salmon
String shortMenu =Dish.menu.stream()
.map(Dish::getName)
.collect(Collectors.joining(/*구분자*/", "));
데이터 수집하기 - 리듀싱과 요약
범용 리듀싱 연산
reducing 팩터리 메서드를 사용하면 연산 내부 로직을 직접 정의할 수 있
다.
int totalCalories = Dish.menu.stream().collect(
Collectors.reducing(
0/*연산의 시작값*/,
Dish::getCalories/*연산의 대상이 되는 값을 추출*/,
(i, j) -> i + j)/*BinaryOperator로 두 값을 합침*/
);
Optional<Dish> maxCalorieDish = Dish.menu.stream().collect(
Collectors.reducing(
/*BinaryOperator 연산을 진행*/
(d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2
)
);
데이터 수집하기 - 그룹화
groupingBy 메서드는 각 요소들을 조건에 따라 묶은 결과값을 만들어낼
수 있다.
// OTHER=[french fries, rice, season fruit, pizza],
// MEAT=[pork, beef, chicken],
// FISH=[prawns, salmon]
Map<Dish.Type, List<Dish>> dishesByType = Dish.menu.stream()
.collect(groupingBy(Dish::getType));
데이터 수집하기 - 그룹화
groupingBy 메서드의 두번째 파라미터로 Collector를 사용할 수 있다.
해당 인자를 사용하면 추가적인 그룹화나 갯수를 세는 등의 작업이 가능
하다.
// {OTHER=4, MEAT=3, FISH=2}
Dish.menu.stream()
.collect(groupingBy(
Dish::getType, Collectors.counting()
));
// OTHER={true=[french fries, rice, season fruit, pizza]}
// MEAT={false=[pork, beef, chicken]}
// FISH={false=[prawns, salmon]}
Dish.menu.stream()
.collect(groupingBy(
Dish::getType,
groupingBy(Dish::isVegetarian)
));
데이터 수집하기 - 그룹화
collectingAndThen 함수를 사용할 경우 결과값을 재가공할 수 있다.
Map<Dish.Type, Optional<Dish>> maxDishes1 = Dish.menu.stream().collect(
groupingBy(
Dish::getType,
Collectors.maxBy(Comparator.comparingInt(Dish::getCalories))
)
);
Map<Dish.Type, Dish> maxDishes2 = Dish.menu.stream().collect(groupingBy(
Dish::getType,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)),
Optional::get
)
));
데이터 수집하기 - 분할
Predicate를 분류함수로 사용하는 그룹화 기능이다.
// {false=[pork, beef, chicken, prawns, salmon],
// true=[french fries, rice, season fruit, pizza]}
Map<Boolean, List<Dish>> partitionedMenu = Dish.menu.stream()
.collect(
Collectors.partitioningBy(Dish::isVegetarian)
);
데이터 수집하기 - 분할
Predicate를 분류함수로 사용하는 그룹화 기능이다.
// {false=[pork, beef, chicken, prawns, salmon],
// true=[french fries, rice, season fruit, pizza]}
Map<Boolean, List<Dish>> partitionedMenu = menu.stream()
.collect(
Collectors.partitioningBy(Dish::isVegetarian)
);
// {false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]},
// true={OTHER=[french fries, rice, season fruit, pizza]}}
Map<Boolean, Map<Type, List<Dish>>> partAndGroupDishes = menu.
stream().
collect(Collectors.partitioningBy(
Dish::isVegetarian,
Collectors.groupingBy(Dish::getType)
));
Collectors인터페이스에 대해서 조금 더 자세히 알아봅시다.
Collector 인터페이스와 구현
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();
}
병렬스트림 사용하기
Stream.iterate(1L, i -> i + 1)
.parallel()
.limit(n)
.reduce(0L, Long::sum);
parallel을 stream에 추가만 하면
연산을 병렬로 수행할 수 있다.
병렬스트림 사용하기
병렬로 처리하기 전 데이터를 작은 단위로 잘라낸다.
if(태스크가 충분히 작거나 더이상 분할할 수 없으면) {
순차적으로 태스크 계산
} else {
태스트를 두 서브 태스크로 분할
태스크가 다시 서브 태스크로 분할되도록 이 메서드를 재귀적으로
호출함
모든 서브 태스크의 연산이 완료될 때까지 기다림
각 서브 태스크의 결과를 합침
}
병렬스트림 사용하기
병렬스트림 사용하기
병렬스트림 사용하기
병렬스트림은 결코 빠르지 않습니
다.
은총알은 존재하지 않아요.
병렬 스트림 처리과정
1. 스레드를 만들고 초기화한다.
2. 데이터를 여러개의 청크로 분리한다.
3. 각 스레드에 청크를 할당하고 계산한다.
4. 각 스레드의 결과를 하나로 병합한다.
병렬스트림 사용하기
병렬스트림 사용하기
// 10ms 소요
public static long iterativeSum(long n) {
long result = 0;
for (long i = 0; i <= n; i++) {
result += i;
}
return result;
}
// 140ms 소요
public static long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.reduce(Long::sum)
.get();
}
1부터 10,000,000까지 값을 더하는 위의 로직은
오히려 고전적인 for-loop방식이 훨씬 빠르다.
병렬스트림 사용하기
// 142ms 소요
public static long parallelSum(long n) {
return Stream.iterate(1L, i -> i + 1).limit(n)
.parallel()
.reduce(Long::sum)
.get();
}
병렬 스트림으로 실행했을 때 오히려 낮은 성능을 보인다.
● iterate가 박싱된 객체를 생성하므로 이를 다시 언박싱 비용이 필
요
● iterate는 독립적인 청크로 분할하기는 어려워 병렬로 실행되지
않음
병렬스트림 사용하기
// 20ms
public static long rangedSum(long n) {
return LongStream.rangeClosed(1, n)
.reduce(Long::sum)
.getAsLong();
}
LongStream + 고정크기로 성능 개선
● rangeClosed를 사용시 기본형을 직접 사용하므로 박싱, 언박싱
에 발생하는 비용을 줄일 수 있다.
● 범위가 고정되어 있으므로 쉽게 청크를 분할할 수 있다.
병렬스트림 사용하기
// 4ms 드디어!!
public static long parallelRangedSum(long n) {
return LongStream.rangeClosed(1, n)
.parallel()
.reduce(Long::sum)
.getAsLong();
}
비로소 기존의 for-loop문보다 빠른 코드를 작성하였다.
하지만 for-loop보다 비용이 결코 작지 않다는 것을 기억하자.
병렬스트림 사용하기
측정하라. 병렬스트림은 항상 순차스트림보다 빠르지 않다.
박싱을 주의하라. 자동박싱과 언박싱과정은 성능을 크게 저하시킨다.
자바에서 제공하는 기본형 특화 스트림을 사용하는 것이 좋다.
순차스트림보다 병렬스트림에서 성능이 떨어지는 연산이 존재한다.
limit나 findFirst 처럼 요소의 순서에 의존하는 연산을 병렬 스트림에서
수행하려면 비싼 비용이 필요하다.
소량의 데이터라면 병렬스트림이 도움되지는 않는다.
소량의 데이터를 처리하는 과정에서 병렬화과정에서 생기는 부가비용
을 상쇄할 수 있을만큼 이득을 얻지 못하기 때문이다.
병렬스트림 사용하기
스트림을 구성하는 자료구조가 적절한지 확인하여라.
ArrayList는 LinkedList보다 효율적으로 분리가 가능하다.
스트림의 특성과 파이프라인의 중간연산이 스트림의 특성을 어떻게 바
꾸느냐에 따라서 분해과정의 성능이 달라질 수 있다. 필터연산이 있을
경우 크기를 예측할 수 없으므로 효과적인 스트림 처리가 되지 않는다.
최종연산과정에서 병합비용을 살펴보아라.
병합비용이 비싸다면 병렬스트림으로 얻은 성능의 이익이 서브스트림
의 부분결과를 합치는 과정에서 상쇄될 수 있다.
병렬스트림 사용하기
정리
● collect는 스트림의 최종연산이다. Collector 구현체에 따라서 연산
하여 최종 결과를 만들어낸다.
● 자바에서는 자주 사용되는 Collector구현체를 모아놓은 Collectors
를 제공한다. 이를 통해서 그룹화나 평균값등의 다양한 작업을 할
수 있다.
● Collectors에 제공되는 메서드들은는다수준의 그룹화나 분할작업
에도 유연하게 대응할 수 있다.
● 필요에 따라서 커스텀 컬렉터를 직접 구현할 수 있다.
● 스트림은 간단하게 병렬처리방식으로 변경할 수 있다.
● 병렬처리방식이 항상 빠른것은 아니므로, 병렬로 데이터를 처리할
경우에는 유의하여 작업을 진행하여야 한다.

More Related Content

What's hot

발표자료 11장
발표자료 11장발표자료 11장
발표자료 11장Juhui Park
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개Sungchul Park
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개beom kyun choi
 
Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기rupert kim
 
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 APIArawn Park
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선daewon jeong
 
Perl Script Document
Perl Script DocumentPerl Script Document
Perl Script Document오석 한
 
러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)명성 정
 
Scala 기초 (4)
Scala 기초 (4)Scala 기초 (4)
Scala 기초 (4)명성 정
 
Scala 기초 (2)
Scala 기초 (2)Scala 기초 (2)
Scala 기초 (2)명성 정
 
Lambda 란 무엇인가
Lambda 란 무엇인가Lambda 란 무엇인가
Lambda 란 무엇인가Vong Sik Kong
 
Java 변수자료형
Java 변수자료형Java 변수자료형
Java 변수자료형Hyosang Hong
 
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...탑크리에듀(구로디지털단지역3번출구 2분거리)
 
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)탑크리에듀(구로디지털단지역3번출구 2분거리)
 
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)MIN SEOK KOO
 

What's hot (20)

발표자료 11장
발표자료 11장발표자료 11장
발표자료 11장
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개
 
Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기
 
JDK 변천사
JDK 변천사JDK 변천사
JDK 변천사
 
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API
 
Pair RDD - Spark
Pair RDD - SparkPair RDD - Spark
Pair RDD - Spark
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
Perl Script Document
Perl Script DocumentPerl Script Document
Perl Script Document
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
 
러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)
 
Scala 기초 (4)
Scala 기초 (4)Scala 기초 (4)
Scala 기초 (4)
 
Scala 기초 (2)
Scala 기초 (2)Scala 기초 (2)
Scala 기초 (2)
 
자바모델 클래스에 날개를달자_롬복(Lombok)
자바모델 클래스에 날개를달자_롬복(Lombok)자바모델 클래스에 날개를달자_롬복(Lombok)
자바모델 클래스에 날개를달자_롬복(Lombok)
 
Lambda 란 무엇인가
Lambda 란 무엇인가Lambda 란 무엇인가
Lambda 란 무엇인가
 
Java lambda
Java lambdaJava lambda
Java lambda
 
Java 변수자료형
Java 변수자료형Java 변수자료형
Java 변수자료형
 
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
 
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
 
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
 

Viewers also liked

ProjectEuler 소개 및 활용법
ProjectEuler 소개 및 활용법ProjectEuler 소개 및 활용법
ProjectEuler 소개 및 활용법Sejong Park
 
Java 8 - New Updates and Why It Matters?
Java 8 - New Updates and Why It Matters?Java 8 - New Updates and Why It Matters?
Java 8 - New Updates and Why It Matters?CTE Solutions Inc.
 
백엔드 스터디 2주
백엔드 스터디 2주백엔드 스터디 2주
백엔드 스터디 2주Chi Hwan Choi
 
안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기DongHwan Yu
 
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Sungchul Park
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰Sungchul Park
 

Viewers also liked (6)

ProjectEuler 소개 및 활용법
ProjectEuler 소개 및 활용법ProjectEuler 소개 및 활용법
ProjectEuler 소개 및 활용법
 
Java 8 - New Updates and Why It Matters?
Java 8 - New Updates and Why It Matters?Java 8 - New Updates and Why It Matters?
Java 8 - New Updates and Why It Matters?
 
백엔드 스터디 2주
백엔드 스터디 2주백엔드 스터디 2주
백엔드 스터디 2주
 
안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기안드로이드를 위한 Gradle 맛들이기
안드로이드를 위한 Gradle 맛들이기
 
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰
 

Similar to 3주차. stream api advance

스트림Api 스터디 2일
스트림Api 스터디   2일스트림Api 스터디   2일
스트림Api 스터디 2일ByungSun Park
 
제5장 집계함수, 그룹함수 사용하기
제5장 집계함수, 그룹함수 사용하기제5장 집계함수, 그룹함수 사용하기
제5장 집계함수, 그룹함수 사용하기sang doc Lee
 
파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄SeongHyun Ahn
 
[자바카페] Elasticsearch Aggregation (2018)
[자바카페] Elasticsearch Aggregation (2018)[자바카페] Elasticsearch Aggregation (2018)
[자바카페] Elasticsearch Aggregation (2018)용호 최
 
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)주영 송
 
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개PgDay.Seoul
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8Sangmin Lee
 
Kubernetes & helm 활용
Kubernetes & helm 활용Kubernetes & helm 활용
Kubernetes & helm 활용SK Telecom
 
[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화AnselmKim
 
Collection framework
Collection frameworkCollection framework
Collection frameworkssuser34b989
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍Young-Beom Rhee
 
12장 상속 (고급)
12장 상속 (고급)12장 상속 (고급)
12장 상속 (고급)유석 남
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰beom kyun choi
 
스트림Api 스터디 1일
스트림Api 스터디 1일스트림Api 스터디 1일
스트림Api 스터디 1일ByungSun Park
 
집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03Kwang Woo NAM
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIjieun kim
 

Similar to 3주차. stream api advance (19)

스트림Api 스터디 2일
스트림Api 스터디   2일스트림Api 스터디   2일
스트림Api 스터디 2일
 
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
 
제5장 집계함수, 그룹함수 사용하기
제5장 집계함수, 그룹함수 사용하기제5장 집계함수, 그룹함수 사용하기
제5장 집계함수, 그룹함수 사용하기
 
파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄
 
[자바카페] Elasticsearch Aggregation (2018)
[자바카페] Elasticsearch Aggregation (2018)[자바카페] Elasticsearch Aggregation (2018)
[자바카페] Elasticsearch Aggregation (2018)
 
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)
MapReduce 실행 샘플 (K-mer Counting, K-means Clustering)
 
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개
 
스트림Api 소개
스트림Api 소개스트림Api 소개
스트림Api 소개
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
Kubernetes & helm 활용
Kubernetes & helm 활용Kubernetes & helm 활용
Kubernetes & helm 활용
 
[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화
 
Collection framework
Collection frameworkCollection framework
Collection framework
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
 
12장 상속 (고급)
12장 상속 (고급)12장 상속 (고급)
12장 상속 (고급)
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰
 
스트림Api 스터디 1일
스트림Api 스터디 1일스트림Api 스터디 1일
스트림Api 스터디 1일
 
집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST API
 

3주차. stream api advance

  • 1. Stream API Javacafe 백엔드 스터디 (자바8)
  • 2. 목차 • 복습 • 데이터 수집하기 • 컬렉터 소개 • 리듀싱과 요약 • 그룹화 및 분할 • Collector 인터페이스와 구현 • 병렬스트림 사용하기 • 병렬 스트림 제대로 사용하기
  • 3. List<Dish> lowCaloricDishes = new ArrayList<>(); // 칼로리가 400이하인 메뉴만 가지고 온다. for (Dish d : menu) { if (d.getCalories() < 400) { lowCaloricDishes.add(d); } } // 칼로리 순으로 정렬 Collections.sort(lowCaloricDishes, new Comparator<Dish>() { public int compare(Dish o1, Dish o2) { return Integer.compare(o1.getCalories(), o2.getCalories()); } }); // 요리 이름만 가지고 온다. List<String> lowCaloricDishesName = new ArrayList<>(); for (Dish d : lowCaloricDishes) { lowCaloricDishesName.add(d.getName()); } // 상위 3개의 결과만 반환한다 List<String> lowCaloricLimit3DisishesName = lowCaloricDishesName.subList(0, 3); System.out.println(lowCaloricLimit3DisishesName); 클래식 자바 스타일, 컬렉션을 활용한 요구사항 구현 두번째 시간 복습
  • 4. Stream API를 활용한다면!! List<String> lowCaloricDishesName = menu.stream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dish::getCalories)) .map(Dish::getName) .collect(toList()); System.out.println(lowCaloricDishesName); 두번째 시간 복습
  • 5. 두번째 시간 복습 • 컬렉션과 스트림 모두 연속된 요소 형식의 값을 저장하는 자료형 인터페이스이다. • 컬렉션은 자료를 저장하는데 특화되어있다. 스트림은 요소들을 연산하기 위한 자료형이다. • 데이터 연산 방식에도 큰 차이가 있다. – 컬렉션 : 연산 과정을 직접 작성하여 한다. 각 로직의 순서에 따라 연산이 순차적으로 진 행된다. – 스트림 : 연산은 라이브러리가 알아서 진행한다. ㄴㄴㄴㄴ종결연산 메서드에서 연산이 한꺼번에 진행 된다. 스트림 vs 컬렉션
  • 6. filter map limit collect 중간연산 최종연산 menu.stream().filter(d -> d.getCalories() > 300) .map(Dish::getName) .limit(3) .collect(toList()); 중간연산은 파이프라인으로 연결 되어 선언식이 최종연산으로 전달 된다. 중간연산 정보를 스트림으로 입력받 아 최종연산에서 한번에 처리한다. 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다. (Lazy) 모든 중간연산을 합친 다음 최종연산에서 한번에 처리한다. 두번째 시간 복습 스트림 API
  • 8. 데이터 수집하기 요구사항 ● 통화별로 트랜잭션을 그룹화한 다음에 해당 통화 의 모든 합계를 계산하시오. Map<Currency, Integer> 형식 반환 ● 트랜잭션을 나라별로 그룹화 한뒤. 각 트랜잭션의 5000이상일 경우를 구분하여 리스트로 반환하시 오. Map<String, Map<Boolean, List<Transaction>>> 반 환
  • 9. 데이터 수집하기 요구사항 : 각 트랜잭션을 Currency로 분류하여 반환하여라. Map<Currency, List<Transaction>>반환 Map<Currency, List<Transaction>> resultCurrencies = new HashMap<>(); for (Transaction transaction : transactions) { Currency currency = transaction.getCurrency(); List<Transaction> transactionsForCurrency = resultCurrencies.get(currency); if (transactionsForCurrency == null) { transactionsForCurrency = new ArrayList<>(); resultCurrencies.put(currency, transactionsForCurrency); } transactionsForCurrency.add(transaction); }
  • 10. 데이터 수집하기 요구사항 : 각 트랜잭션을 Currency로 묶은다음 반환하여라. Map<Currency, List<>> transactionsByCurrencies = transactions.stream() .collect(groupingBy(Transaction::getCurrency));
  • 11. 데이터 수집하기 - 컬렉터 소개 ● collect는 Stream 최종연산 메서드 ● collect 종결연산 메서드 스트림의 결과를 수집 ● 인자로 Collector<T, A, R>의 구현체를 받는다. ● Collector에서 결과값에 대한 연산작업이 정의 transactions.stream() .collect(Collectors.groupingBy(Transaction::getCurrency));
  • 12. 데이터 수집하기 - 컬렉터 소개
  • 13. 데이터 수집하기 - 컬렉터 소개 미리 정의된 컬렉터 Collectors 자주 사용되는 Collector의 구현체를 제공하는 팩터리 메서드들의 집합 클 래스 ● 스트림 요소를 하나의 값으로 리듀스 또는 요약 ● 스트림 요소 그룹화 ● 스트림 요소 분할
  • 14. 데이터 수집하기 - 리듀싱과 요약 각 요소의 값을 줄여가며, 하나의 결과값을 반환 각 요소들의 최댓값, 최솟값, 평균등의 값을 도출
  • 15. 데이터 수집하기 - 리듀싱과 요약 최댓값과 최솟값 검색하기 maxBy, minBy메서드를 사용하여 최댓값과 최솟값을 찾을 수 있다. Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories); Dish mostCalorieDish = menu.stream() .collect(Collectors.maxBy(dishCaloriesComparator)) .get(); Dish lowestCalorieDish = menu.stream() .collect(Collectors.minBy(dishCaloriesComparator)) .get();
  • 16. 데이터 수집하기 - 리듀싱과 요약 요소의 합계 및 평균 구하기 summingInt, SummingLong, SummingDouble : 요소의 합 도출 averageInt, averageLong, averageDouble : 요소의 평균 도출 int totalCalories = Dish.menu.stream() .collect(Collectors.summingInt(Dish::getCalories)); Double collect = Dish.menu.stream() .collect(Collectors.averagingInt(Dish::getCalories));
  • 17. 데이터 수집하기 - 리듀싱과 요약 요약연산 summarizingInt로 요소의 합계, 평균, 최솟값, 최댓값의 정보를 한꺼번에 가져올 수 있다. // count=9, sum=4300, min=120, average=477.777778, max=800 IntSummaryStatistics menuStatistics = Dish.menu.stream(). collect( Collectors.summarizingInt(Dish::getCalories) );
  • 18. 데이터 수집하기 - 리듀싱과 요약 문자열 연결 joining메서드를 사용하여 각 문자열 요소를 합쳐 결과로 반환할 수 있다. //pork, beef, chicken ... pizza, prawns, salmon String shortMenu =Dish.menu.stream() .map(Dish::getName) .collect(Collectors.joining(/*구분자*/", "));
  • 19. 데이터 수집하기 - 리듀싱과 요약 범용 리듀싱 연산 reducing 팩터리 메서드를 사용하면 연산 내부 로직을 직접 정의할 수 있 다. int totalCalories = Dish.menu.stream().collect( Collectors.reducing( 0/*연산의 시작값*/, Dish::getCalories/*연산의 대상이 되는 값을 추출*/, (i, j) -> i + j)/*BinaryOperator로 두 값을 합침*/ ); Optional<Dish> maxCalorieDish = Dish.menu.stream().collect( Collectors.reducing( /*BinaryOperator 연산을 진행*/ (d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2 ) );
  • 20. 데이터 수집하기 - 그룹화 groupingBy 메서드는 각 요소들을 조건에 따라 묶은 결과값을 만들어낼 수 있다. // OTHER=[french fries, rice, season fruit, pizza], // MEAT=[pork, beef, chicken], // FISH=[prawns, salmon] Map<Dish.Type, List<Dish>> dishesByType = Dish.menu.stream() .collect(groupingBy(Dish::getType));
  • 21. 데이터 수집하기 - 그룹화 groupingBy 메서드의 두번째 파라미터로 Collector를 사용할 수 있다. 해당 인자를 사용하면 추가적인 그룹화나 갯수를 세는 등의 작업이 가능 하다. // {OTHER=4, MEAT=3, FISH=2} Dish.menu.stream() .collect(groupingBy( Dish::getType, Collectors.counting() )); // OTHER={true=[french fries, rice, season fruit, pizza]} // MEAT={false=[pork, beef, chicken]} // FISH={false=[prawns, salmon]} Dish.menu.stream() .collect(groupingBy( Dish::getType, groupingBy(Dish::isVegetarian) ));
  • 22. 데이터 수집하기 - 그룹화 collectingAndThen 함수를 사용할 경우 결과값을 재가공할 수 있다. Map<Dish.Type, Optional<Dish>> maxDishes1 = Dish.menu.stream().collect( groupingBy( Dish::getType, Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)) ) ); Map<Dish.Type, Dish> maxDishes2 = Dish.menu.stream().collect(groupingBy( Dish::getType, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)), Optional::get ) ));
  • 23. 데이터 수집하기 - 분할 Predicate를 분류함수로 사용하는 그룹화 기능이다. // {false=[pork, beef, chicken, prawns, salmon], // true=[french fries, rice, season fruit, pizza]} Map<Boolean, List<Dish>> partitionedMenu = Dish.menu.stream() .collect( Collectors.partitioningBy(Dish::isVegetarian) );
  • 24. 데이터 수집하기 - 분할 Predicate를 분류함수로 사용하는 그룹화 기능이다. // {false=[pork, beef, chicken, prawns, salmon], // true=[french fries, rice, season fruit, pizza]} Map<Boolean, List<Dish>> partitionedMenu = menu.stream() .collect( Collectors.partitioningBy(Dish::isVegetarian) ); // {false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]}, // true={OTHER=[french fries, rice, season fruit, pizza]}} Map<Boolean, Map<Type, List<Dish>>> partAndGroupDishes = menu. stream(). collect(Collectors.partitioningBy( Dish::isVegetarian, Collectors.groupingBy(Dish::getType) ));
  • 25. Collectors인터페이스에 대해서 조금 더 자세히 알아봅시다. Collector 인터페이스와 구현 public interface Collector<T, A, R> { Supplier<A> supplier(); BiConsumer<A, T> accumulator(); BinaryOperator<A> combiner(); Function<A, R> finisher(); Set<Characteristics> characteristics(); }
  • 26. 병렬스트림 사용하기 Stream.iterate(1L, i -> i + 1) .parallel() .limit(n) .reduce(0L, Long::sum); parallel을 stream에 추가만 하면 연산을 병렬로 수행할 수 있다.
  • 27. 병렬스트림 사용하기 병렬로 처리하기 전 데이터를 작은 단위로 잘라낸다. if(태스크가 충분히 작거나 더이상 분할할 수 없으면) { 순차적으로 태스크 계산 } else { 태스트를 두 서브 태스크로 분할 태스크가 다시 서브 태스크로 분할되도록 이 메서드를 재귀적으로 호출함 모든 서브 태스크의 연산이 완료될 때까지 기다림 각 서브 태스크의 결과를 합침 }
  • 30. 병렬스트림 사용하기 병렬스트림은 결코 빠르지 않습니 다. 은총알은 존재하지 않아요.
  • 31. 병렬 스트림 처리과정 1. 스레드를 만들고 초기화한다. 2. 데이터를 여러개의 청크로 분리한다. 3. 각 스레드에 청크를 할당하고 계산한다. 4. 각 스레드의 결과를 하나로 병합한다. 병렬스트림 사용하기
  • 32. 병렬스트림 사용하기 // 10ms 소요 public static long iterativeSum(long n) { long result = 0; for (long i = 0; i <= n; i++) { result += i; } return result; } // 140ms 소요 public static long sequentialSum(long n) { return Stream.iterate(1L, i -> i + 1) .limit(n) .reduce(Long::sum) .get(); } 1부터 10,000,000까지 값을 더하는 위의 로직은 오히려 고전적인 for-loop방식이 훨씬 빠르다.
  • 33. 병렬스트림 사용하기 // 142ms 소요 public static long parallelSum(long n) { return Stream.iterate(1L, i -> i + 1).limit(n) .parallel() .reduce(Long::sum) .get(); } 병렬 스트림으로 실행했을 때 오히려 낮은 성능을 보인다. ● iterate가 박싱된 객체를 생성하므로 이를 다시 언박싱 비용이 필 요 ● iterate는 독립적인 청크로 분할하기는 어려워 병렬로 실행되지 않음
  • 34. 병렬스트림 사용하기 // 20ms public static long rangedSum(long n) { return LongStream.rangeClosed(1, n) .reduce(Long::sum) .getAsLong(); } LongStream + 고정크기로 성능 개선 ● rangeClosed를 사용시 기본형을 직접 사용하므로 박싱, 언박싱 에 발생하는 비용을 줄일 수 있다. ● 범위가 고정되어 있으므로 쉽게 청크를 분할할 수 있다.
  • 35. 병렬스트림 사용하기 // 4ms 드디어!! public static long parallelRangedSum(long n) { return LongStream.rangeClosed(1, n) .parallel() .reduce(Long::sum) .getAsLong(); } 비로소 기존의 for-loop문보다 빠른 코드를 작성하였다. 하지만 for-loop보다 비용이 결코 작지 않다는 것을 기억하자.
  • 36. 병렬스트림 사용하기 측정하라. 병렬스트림은 항상 순차스트림보다 빠르지 않다. 박싱을 주의하라. 자동박싱과 언박싱과정은 성능을 크게 저하시킨다. 자바에서 제공하는 기본형 특화 스트림을 사용하는 것이 좋다. 순차스트림보다 병렬스트림에서 성능이 떨어지는 연산이 존재한다. limit나 findFirst 처럼 요소의 순서에 의존하는 연산을 병렬 스트림에서 수행하려면 비싼 비용이 필요하다. 소량의 데이터라면 병렬스트림이 도움되지는 않는다. 소량의 데이터를 처리하는 과정에서 병렬화과정에서 생기는 부가비용 을 상쇄할 수 있을만큼 이득을 얻지 못하기 때문이다.
  • 37. 병렬스트림 사용하기 스트림을 구성하는 자료구조가 적절한지 확인하여라. ArrayList는 LinkedList보다 효율적으로 분리가 가능하다. 스트림의 특성과 파이프라인의 중간연산이 스트림의 특성을 어떻게 바 꾸느냐에 따라서 분해과정의 성능이 달라질 수 있다. 필터연산이 있을 경우 크기를 예측할 수 없으므로 효과적인 스트림 처리가 되지 않는다. 최종연산과정에서 병합비용을 살펴보아라. 병합비용이 비싸다면 병렬스트림으로 얻은 성능의 이익이 서브스트림 의 부분결과를 합치는 과정에서 상쇄될 수 있다.
  • 39. 정리 ● collect는 스트림의 최종연산이다. Collector 구현체에 따라서 연산 하여 최종 결과를 만들어낸다. ● 자바에서는 자주 사용되는 Collector구현체를 모아놓은 Collectors 를 제공한다. 이를 통해서 그룹화나 평균값등의 다양한 작업을 할 수 있다. ● Collectors에 제공되는 메서드들은는다수준의 그룹화나 분할작업 에도 유연하게 대응할 수 있다. ● 필요에 따라서 커스텀 컬렉터를 직접 구현할 수 있다. ● 스트림은 간단하게 병렬처리방식으로 변경할 수 있다. ● 병렬처리방식이 항상 빠른것은 아니므로, 병렬로 데이터를 처리할 경우에는 유의하여 작업을 진행하여야 한다.