5. 첫번째 시간 복습 - 함수형 인터페이스
● 하나의 추상 메서드를 가진 인터페이스만 람다로 사용할 수 있다.
이러한 인터페이스를 함수형 인터페이스라고 한다.
● 인터페이스 내부에 선언된 유일한 메서드에 람다의 몸체가 정의된다.
● 함수형 인터페이스에 디폴트 메서드가 여럿 있더라도,
추상 메서드가 하나라면 함수형 인터페이스이다.
● 어노테이션 @FunctionalInterface를 클래스 상단에 붙여
명시적으로 함수형 인터페이스라는 것을 표기해줄 수 있다.
6. 첫번째 시간 복습 - 디폴트 메서드
default 키워드를 사용하면 인터페이스에 메서드를 바로 설정 가
능
기존의 구현체 구조에 영향을 주지 않고 새로운 기능을 추가
<Interface>
List
ArrayList
LinkedList
Stack
ArrayList
LinkedList
Stack
7. 첫번째 시간 복습 - 메서드 레퍼런스
람다를 간결하게 쓸 수 있도록 도와주는 문법
클래스(객체)명과 메서드명 사이에 구분자(::)를 붙여 사용한다.
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);
클래식 자바 스타일, 컬렉션을 활용한 요구사항 구현
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)
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
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 타입으로 변환 가능