ݺߣ

ݺߣShare a Scribd company logo
Stream API
Javacafe 백엔드 스터디 (자바8)
목차
• 첫번째 시간 복습
• 스트림 API 소개
• 컬렉션 vs 스트림API
• 스트림 API 특징
• Optional
• 스트림 API 활용
• Stream API 데이터 연산
• 스트림 생성
• 기본형 특화 스트림
첫번째 시간 복습 - 람다
익명 클래스에서 람다식으로
첫번째 시간 복습 - 람다
첫번째 시간 복습 - 함수형 인터페이스
● 하나의 추상 메서드를 가진 인터페이스만 람다로 사용할 수 있다.
이러한 인터페이스를 함수형 인터페이스라고 한다.
● 인터페이스 내부에 선언된 유일한 메서드에 람다의 몸체가 정의된다.
● 함수형 인터페이스에 디폴트 메서드가 여럿 있더라도,
추상 메서드가 하나라면 함수형 인터페이스이다.
● 어노테이션 @FunctionalInterface를 클래스 상단에 붙여
명시적으로 함수형 인터페이스라는 것을 표기해줄 수 있다.
첫번째 시간 복습 - 디폴트 메서드
default 키워드를 사용하면 인터페이스에 메서드를 바로 설정 가
능
기존의 구현체 구조에 영향을 주지 않고 새로운 기능을 추가
<Interface>
List
ArrayList
LinkedList
Stack
ArrayList
LinkedList
Stack
첫번째 시간 복습 - 메서드 레퍼런스
람다를 간결하게 쓸 수 있도록 도와주는 문법
클래스(객체)명과 메서드명 사이에 구분자(::)를 붙여 사용한다.
Java.util.function 패키지
첫번째 시간 복습 - 기본 제공 함수형 인터페이스
스트림 API 소개
스트림 API 소개
요구사항
칼로리가 400이하인 요리를 추출
칼로리 순으로 정렬하고
상위 3개의 이름을 출력
스트림 API 소개
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);
클래식 자바 스타일, 컬렉션을 활용한 요구사항 구현
스트림 API 소개
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);
스트림 API 소개
또 다른 요구사항
1. 300칼로리 이하인 메뉴를 다이어트로, 아닐 경우에는 일반으로 나
누어라
2. 가장 칼로리가 높은 메뉴를 찾아라
스트림 API 특성
선언형 프로그래밍
SELECT *
FROM Products
WHERE (Price BETWEEN 10 AND 20)
AND NOT CategoryID IN (1,2,3);
● 명령형 프로그래밍은 어떻게 해결할지에 대해서 집중
● 선언형 프로그래밍은 무엇을 하여야 하는지에 대해서 집중
● 명령형 프로그래밍보다 선언형 프로그래밍이 좋은가?
○ 구체적인 작동 순서를 나열하지 않고, 알고리즘에만 집중 할 수 있다.
○ 이미 구현된 것을 사용. 성능이 빠르다.
○ 구체적인 작동 순서를 나열하지 않기 때문에. 명령형보다 버그 적다.
스트림 API 특성
조립할 수 있음
● 스트림을 조작할 수 있는 다양한 메서드를 제공한다.
● Stream API에서는 이 메서드들을 연결, 복잡한 연산을 처리하는 로직
을 쉽고 유연하게 작성해 낼 수 있다.
스트림 API 특성
병렬화
List<String> dishs = menu.parallelStream()
.filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.collect(toList());
다음과 같이 병렬스트림이라고 선언만
하면
병렬로 데이터를 처리할 수 있다.
List<String> dishs = menu.stream()
.filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.collect(toList());
스트림 API 특성
• 컬렉션과 스트림 모두 연속된 요소 형식의 값을 저장하는
자료구조의 인터페이스를 제공한다.
• 둘 다 순서에 따라 순차적으로 요소에 접근한다.
• 컬렉션과 스트림의 가장 큰 차이는 데이터를 언제 계산하
느냐 이다.
– 컬렉션 : 각 계산식을 만날때마다 데이터가 계산된다.
– 스트림 : 최종연산이 실행될 때에 데이터가 계산된다.
스트림 vs 컬렉션
스트림 API 특성
• 컬렉션
– 자료구조이므로 데이터에 접근, 읽기, 변경, 저장
같은 연산이 주요 관심사이다. (직접 데이터 핸들
링)
– 데이터에 접근하는 방법을 직접 작성해야 한다.
• 스트림
– Filter, sorted, map 처럼 계산식(람다)을 표현하는
것이 주요 관심사이다. (계산식을 JVM으로 던진
다.)
– 데이터에 접근하는 방법이 추상화 되어 있다.
스트림 vs 컬렉션 - 데이터 접근 측면
스트림 API 특성
스트림 vs 컬렉션 - 데이터 계산 측면
• 컬렉션
– 작업을 위해서 Iterator로 모든 요소를 순환해야 한다.
– 메모리에 모든 요소가 올라간다.
– 모든 요소가 메모리에 올라가 있는 상태에서 요소를 누적시
키며 결과를 계산한다.
– 메모리 사용량 연산속도
• 스트림
– 계산식(알고리즘 or 람다)을 미리 적어두고 계산시에 람다로
JVM에 넘긴다.
– 내부에서 요소를 어떻게 메모리에 올리는 지는 관심사가 아
니다. (블랙박스)
– 계산 요청시 결과가 바로 리턴된다.
– 메모리 사용량 연산속도
스트림 API 특성
filter map limit collect
중간연산 최종연산
menu.stream().filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
중간연산은 파이프라인으로 연결
되어 선언식이 최종연산으로 전달
된다.
중간연산 정보를 스트림으로 입력받
아 최종연산에서 한번에 처리한다.
단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다. (Lazy)
모든 중간연산을 합친 다음 최종연산에서 한번에 처리한다.
스트림 API 특성
스트림 연산
• 스트림은 2가지로 연산이 구분된다.
– Filter, map, limit는 서로 연결되어 파이프라인
을 형성한다.
– Collect로 마지막 파이프라인을 수행후 완료한
다.
• 중간연산 (Intermediate Operation)
• 최종연산 (Terminal Operation)
Optional NPE의 공포에서 벗어나기!
흔하게 만날 수 있는
NullPointerException
Optional NPE의 공포에서 벗어나기!
String version = "UNKNOWN";
if(computer != null){
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null){
USB usb = soundcard.getUSB();
if(usb != null){
version = usb.getVersion();
}
}
}
NullPointerException을 예방하기 위해서는..
Optional NPE의 공포에서 벗어나기!
Optional이란?
● 값이 있거나 또는 없는 경우를 표현하기 위한 클래스
public class Computer {
private Optional<Soundcard> soundcard;
public Optional<Soundcard> getSoundcard() {...}
...
}
// Optional을 사용하면 사용자에게 Null이 나온다는 것을 경고해 줄 수 있다.
if(soundcard.isPresent()){
System.out.println(soundcard.get());
}
// 다양한 부가기능도 제공한다. 값이 없을 경우에 대한 기본값 설정가능
Soundcard soundcard = maybeSoundcard.orElse(new Soundcard("defaut"));
Optional NPE의 공포에서 벗어나기!
usb 객체의 값이 null이 아니면서 버전이 “3.0”이라면 “ok”를 출력하라
// 클래식 자바에서의 요구사항 구현
USB usb = ...;
if(usb != null && "3.0".equals(usb.getVersion())){
System.out.println("ok");
}
// Optional을 사용하였을 경우.
Optional<USB> maybeUSB = ...;
maybeUSB.filter(usb -> "3.0".equals(usb.getVersion())
.ifPresent(() -> System.out.println("ok"));
참조 :
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
스트림 API 활용
스트림 API 활용 - 필터링/슬라이싱
filter
Predicate를 인자로 받아서 참인 요소만을 반환
스트림 API 활용 - 필터링/슬라이싱
distinct
유일한 값을 반환한다.
스트림 API 활용 - 필터링/슬라이싱
limit
지정된 숫자만큼 반환한다.
스트림 API 활용 - 필터링/슬라이싱
skip
지정된 숫자를 무시하고 나머지를 반환한다.
스트림 API 활용 - 매핑
map
스트림의 T객체를 U로 변환. 파라미터로Function<T,U>를 사용
스트림 API 활용 - 매핑
flatMap
각 요소의 값을 분해하여 스트림으로 변환한다.
스트림 API 활용 - 검색과 매칭
anyMatch
Predicate가 적어도 한 요소와 일치하는지 확인한다.
스트림 API 활용 - 검색과 매칭
allMatch
Predicate가 모든 요소와 일치하는지 확인한다.
스트림 API 활용 - 검색과 매칭
noneMatch
Predicate가 모든 요소와 불일치하는지 확인한다.
findAny
현재 스트림에서 임의의 요소를 반환한다.
스트림 API 활용 - 검색과 매칭
()
findFirst
현재 스트림에서 첫번째 요소를 반환한다.
스트림 API 활용 - 검색과 매칭
()
reduce [연산]
reduce(init, operator) 또는 reduce(operator) 형태로 사용
스트림 API 활용 - 리듀싱
reduce [최댓값, 최솟값]
스트림 API 활용 - 리듀싱
sort
Comparator를 사용. 스트림의 요소를 정렬
스트림 API 활용 - sort
스트림 API 활용 - 스트림 생성하기
Stream static 메서드 “of” 사용 Stream.of(data...)
Arrays static 메서드 “stream” 사용 Arrays.stream(Array[])
Stream static 메서드 “iterator” 사용 Stream.iterator(seed, operator);
Stream static 메서드 “generate” 사용 Stream.generate(() -> T)
스트림 API 활용 - 기본형 특화 스트림
숫자집합 스트림에서 연산에서 스트림은 sum과 같은 연산에 대한 메서드는 제공해주지 않는
다.
reduce를 사용하여 데이터를 연산할수는 있지만 직관적이지는 않음
그리고 Autoboxing에 따른 성능저하
스트림 API 활용 - 기본형 특화 스트림
숫자형일 경우에서 사용할 수 있도록 자바는 세가지 형태의 기본형 특화 스트림을
제공
● IntStream
● LongStream
● DoubleStream
숫자형일 경우 사용 가능한 메서드를 제공
필요에 따라 Wrapper 타입으로 변환 가능
스트림 API 활용 - 기본형 특화 스트림 생성
다음시간 - 데이터 수집하기
메뉴를 유형별로 분류하여 아래와 같은 형태로 나타내어라
Map<Type, List<Dish>>
다음시간 - 병렬 스트림
No silver bullet.

More Related Content

자바8강의 2강. Stream API

  • 1. Stream API Javacafe 백엔드 스터디 (자바8)
  • 2. 목차 • 첫번째 시간 복습 • 스트림 API 소개 • 컬렉션 vs 스트림API • 스트림 API 특징 • Optional • 스트림 API 활용 • Stream API 데이터 연산 • 스트림 생성 • 기본형 특화 스트림
  • 3. 첫번째 시간 복습 - 람다 익명 클래스에서 람다식으로
  • 5. 첫번째 시간 복습 - 함수형 인터페이스 ● 하나의 추상 메서드를 가진 인터페이스만 람다로 사용할 수 있다. 이러한 인터페이스를 함수형 인터페이스라고 한다. ● 인터페이스 내부에 선언된 유일한 메서드에 람다의 몸체가 정의된다. ● 함수형 인터페이스에 디폴트 메서드가 여럿 있더라도, 추상 메서드가 하나라면 함수형 인터페이스이다. ● 어노테이션 @FunctionalInterface를 클래스 상단에 붙여 명시적으로 함수형 인터페이스라는 것을 표기해줄 수 있다.
  • 6. 첫번째 시간 복습 - 디폴트 메서드 default 키워드를 사용하면 인터페이스에 메서드를 바로 설정 가 능 기존의 구현체 구조에 영향을 주지 않고 새로운 기능을 추가 <Interface> List ArrayList LinkedList Stack ArrayList LinkedList Stack
  • 7. 첫번째 시간 복습 - 메서드 레퍼런스 람다를 간결하게 쓸 수 있도록 도와주는 문법 클래스(객체)명과 메서드명 사이에 구분자(::)를 붙여 사용한다.
  • 8. Java.util.function 패키지 첫번째 시간 복습 - 기본 제공 함수형 인터페이스
  • 10. 스트림 API 소개 요구사항 칼로리가 400이하인 요리를 추출 칼로리 순으로 정렬하고 상위 3개의 이름을 출력
  • 11. 스트림 API 소개 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); 클래식 자바 스타일, 컬렉션을 활용한 요구사항 구현
  • 12. 스트림 API 소개 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);
  • 13. 스트림 API 소개 또 다른 요구사항 1. 300칼로리 이하인 메뉴를 다이어트로, 아닐 경우에는 일반으로 나 누어라 2. 가장 칼로리가 높은 메뉴를 찾아라
  • 14. 스트림 API 특성 선언형 프로그래밍 SELECT * FROM Products WHERE (Price BETWEEN 10 AND 20) AND NOT CategoryID IN (1,2,3); ● 명령형 프로그래밍은 어떻게 해결할지에 대해서 집중 ● 선언형 프로그래밍은 무엇을 하여야 하는지에 대해서 집중 ● 명령형 프로그래밍보다 선언형 프로그래밍이 좋은가? ○ 구체적인 작동 순서를 나열하지 않고, 알고리즘에만 집중 할 수 있다. ○ 이미 구현된 것을 사용. 성능이 빠르다. ○ 구체적인 작동 순서를 나열하지 않기 때문에. 명령형보다 버그 적다.
  • 15. 스트림 API 특성 조립할 수 있음 ● 스트림을 조작할 수 있는 다양한 메서드를 제공한다. ● Stream API에서는 이 메서드들을 연결, 복잡한 연산을 처리하는 로직 을 쉽고 유연하게 작성해 낼 수 있다.
  • 16. 스트림 API 특성 병렬화 List<String> dishs = menu.parallelStream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dish::getCalories)) .collect(toList()); 다음과 같이 병렬스트림이라고 선언만 하면 병렬로 데이터를 처리할 수 있다. List<String> dishs = menu.stream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dish::getCalories)) .collect(toList());
  • 17. 스트림 API 특성 • 컬렉션과 스트림 모두 연속된 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공한다. • 둘 다 순서에 따라 순차적으로 요소에 접근한다. • 컬렉션과 스트림의 가장 큰 차이는 데이터를 언제 계산하 느냐 이다. – 컬렉션 : 각 계산식을 만날때마다 데이터가 계산된다. – 스트림 : 최종연산이 실행될 때에 데이터가 계산된다. 스트림 vs 컬렉션
  • 18. 스트림 API 특성 • 컬렉션 – 자료구조이므로 데이터에 접근, 읽기, 변경, 저장 같은 연산이 주요 관심사이다. (직접 데이터 핸들 링) – 데이터에 접근하는 방법을 직접 작성해야 한다. • 스트림 – Filter, sorted, map 처럼 계산식(람다)을 표현하는 것이 주요 관심사이다. (계산식을 JVM으로 던진 다.) – 데이터에 접근하는 방법이 추상화 되어 있다. 스트림 vs 컬렉션 - 데이터 접근 측면
  • 19. 스트림 API 특성 스트림 vs 컬렉션 - 데이터 계산 측면 • 컬렉션 – 작업을 위해서 Iterator로 모든 요소를 순환해야 한다. – 메모리에 모든 요소가 올라간다. – 모든 요소가 메모리에 올라가 있는 상태에서 요소를 누적시 키며 결과를 계산한다. – 메모리 사용량 연산속도 • 스트림 – 계산식(알고리즘 or 람다)을 미리 적어두고 계산시에 람다로 JVM에 넘긴다. – 내부에서 요소를 어떻게 메모리에 올리는 지는 관심사가 아 니다. (블랙박스) – 계산 요청시 결과가 바로 리턴된다. – 메모리 사용량 연산속도
  • 20. 스트림 API 특성 filter map limit collect 중간연산 최종연산 menu.stream().filter(d -> d.getCalories() > 300) .map(Dish::getName) .limit(3) .collect(toList()); 중간연산은 파이프라인으로 연결 되어 선언식이 최종연산으로 전달 된다. 중간연산 정보를 스트림으로 입력받 아 최종연산에서 한번에 처리한다. 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다. (Lazy) 모든 중간연산을 합친 다음 최종연산에서 한번에 처리한다.
  • 21. 스트림 API 특성 스트림 연산 • 스트림은 2가지로 연산이 구분된다. – Filter, map, limit는 서로 연결되어 파이프라인 을 형성한다. – Collect로 마지막 파이프라인을 수행후 완료한 다. • 중간연산 (Intermediate Operation) • 최종연산 (Terminal Operation)
  • 22. Optional NPE의 공포에서 벗어나기! 흔하게 만날 수 있는 NullPointerException
  • 23. Optional NPE의 공포에서 벗어나기! String version = "UNKNOWN"; if(computer != null){ Soundcard soundcard = computer.getSoundcard(); if(soundcard != null){ USB usb = soundcard.getUSB(); if(usb != null){ version = usb.getVersion(); } } } NullPointerException을 예방하기 위해서는..
  • 24. Optional NPE의 공포에서 벗어나기! Optional이란? ● 값이 있거나 또는 없는 경우를 표현하기 위한 클래스 public class Computer { private Optional<Soundcard> soundcard; public Optional<Soundcard> getSoundcard() {...} ... } // Optional을 사용하면 사용자에게 Null이 나온다는 것을 경고해 줄 수 있다. if(soundcard.isPresent()){ System.out.println(soundcard.get()); } // 다양한 부가기능도 제공한다. 값이 없을 경우에 대한 기본값 설정가능 Soundcard soundcard = maybeSoundcard.orElse(new Soundcard("defaut"));
  • 25. Optional NPE의 공포에서 벗어나기! usb 객체의 값이 null이 아니면서 버전이 “3.0”이라면 “ok”를 출력하라 // 클래식 자바에서의 요구사항 구현 USB usb = ...; if(usb != null && "3.0".equals(usb.getVersion())){ System.out.println("ok"); } // Optional을 사용하였을 경우. Optional<USB> maybeUSB = ...; maybeUSB.filter(usb -> "3.0".equals(usb.getVersion()) .ifPresent(() -> System.out.println("ok")); 참조 : http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
  • 27. 스트림 API 활용 - 필터링/슬라이싱 filter Predicate를 인자로 받아서 참인 요소만을 반환
  • 28. 스트림 API 활용 - 필터링/슬라이싱 distinct 유일한 값을 반환한다.
  • 29. 스트림 API 활용 - 필터링/슬라이싱 limit 지정된 숫자만큼 반환한다.
  • 30. 스트림 API 활용 - 필터링/슬라이싱 skip 지정된 숫자를 무시하고 나머지를 반환한다.
  • 31. 스트림 API 활용 - 매핑 map 스트림의 T객체를 U로 변환. 파라미터로Function<T,U>를 사용
  • 32. 스트림 API 활용 - 매핑 flatMap 각 요소의 값을 분해하여 스트림으로 변환한다.
  • 33. 스트림 API 활용 - 검색과 매칭 anyMatch Predicate가 적어도 한 요소와 일치하는지 확인한다.
  • 34. 스트림 API 활용 - 검색과 매칭 allMatch Predicate가 모든 요소와 일치하는지 확인한다.
  • 35. 스트림 API 활용 - 검색과 매칭 noneMatch Predicate가 모든 요소와 불일치하는지 확인한다.
  • 36. findAny 현재 스트림에서 임의의 요소를 반환한다. 스트림 API 활용 - 검색과 매칭 ()
  • 37. findFirst 현재 스트림에서 첫번째 요소를 반환한다. 스트림 API 활용 - 검색과 매칭 ()
  • 38. reduce [연산] reduce(init, operator) 또는 reduce(operator) 형태로 사용 스트림 API 활용 - 리듀싱
  • 39. reduce [최댓값, 최솟값] 스트림 API 활용 - 리듀싱
  • 40. sort Comparator를 사용. 스트림의 요소를 정렬 스트림 API 활용 - sort
  • 41. 스트림 API 활용 - 스트림 생성하기 Stream static 메서드 “of” 사용 Stream.of(data...) Arrays static 메서드 “stream” 사용 Arrays.stream(Array[]) Stream static 메서드 “iterator” 사용 Stream.iterator(seed, operator); Stream static 메서드 “generate” 사용 Stream.generate(() -> T)
  • 42. 스트림 API 활용 - 기본형 특화 스트림 숫자집합 스트림에서 연산에서 스트림은 sum과 같은 연산에 대한 메서드는 제공해주지 않는 다. reduce를 사용하여 데이터를 연산할수는 있지만 직관적이지는 않음 그리고 Autoboxing에 따른 성능저하
  • 43. 스트림 API 활용 - 기본형 특화 스트림 숫자형일 경우에서 사용할 수 있도록 자바는 세가지 형태의 기본형 특화 스트림을 제공 ● IntStream ● LongStream ● DoubleStream 숫자형일 경우 사용 가능한 메서드를 제공 필요에 따라 Wrapper 타입으로 변환 가능
  • 44. 스트림 API 활용 - 기본형 특화 스트림 생성
  • 45. 다음시간 - 데이터 수집하기 메뉴를 유형별로 분류하여 아래와 같은 형태로 나타내어라 Map<Type, List<Dish>>
  • 46. 다음시간 - 병렬 스트림 No silver bullet.