SlideShare a Scribd company logo
1 of 40
동작 파라미터와 람다
- Java 8 in Action
이진우
진행 순서
1. 자바의 변화 배경
2. 동작 파라미터화 코드 전달하기
3. 람다 표현식
1. 자바의 변화 배경
프로그래밍 패러다임의 변화
자바의 변화 배경
1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … )
2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화
자바의 변화 배경
1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … ) -> 함수형 인터페이스, 람다, 메서드 레퍼런스
2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화 -> 스트림 API
자바의 변화 배경
1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … ) -> 함수형 인터페이스, 람다, 메서드 레퍼런스
2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화 -> 스트림 API
함수형 프로그래밍의 도입
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isHidden();
}
});
File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden());
함수형 프로그래밍의 도입
// 익명 내부 클래스
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isHidden();
}
});
// 람다식
File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden());
함수형 프로그래밍의 도입
// 익명 내부 클래스
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isHidden();
}
});
// 람다식
File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden());
// 메서드 레퍼런스
File[] hiddenFiles2 = new File(".").listFiles(File::isHidden);
녹색 사과 필터링하기
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
무거운 사과 필터링하기
public static List<Apple> filterHeavyApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
▬ if문 외에는 전부 동일, 코드의 중복 발생 -> 필터링 전략 추출
필터링 전략 추출
public static boolean isGreenApple(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
▬ 자바 8에 도입된 Predicate 인터페이스를 이용하면 boolean을 반환하는 함수를 담을 수 있다.
필터링 전략 추출
► 한결 개선된 코드
List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple);
List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);
▬ Predicate로 메서드 레퍼런스를 담는다.
Predicate p = FilteringApples::isGreenApple
Predicate p = FilteringApples::isHeavyApple
필터링 전략 추출
► 한결 개선된 코드
List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple);
List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);
▬ Predicate로 메서드 레퍼런스를 담는다.
Predicate p = FilteringApples::isGreenApple
Predicate p = FilteringApples::isHeavyApple
▬ 한두 번만 사용할 메서드를 요구사항마다 정의하는 것은 비효율.
람다를 이용해서 간단히 구현 가능. 물론 코드의 명확성을 우선시한다면 메서드 레퍼런스 활용도 바람직.
List<Apple> greenApples2 = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
List<Apple> heavyApples2 = filterApples(inventory, (Apple a) -> a.getWeight() > 150);
List<Apple> weirdApples = filterApples(inventory, (Apple a) -> a.getWeight() < 80 ||
"brown".equals(a.getColor()));
2. 동작 파라미터화 코드 전달하기
For. 잦은 요구사항에 대응하는 유연하고 간결한 코드 구현
잦은 요구사항 변경
► 사과 재고 관리 프로그램
2016.09.20 – 농부: 녹색 사과를 모두 찾고 싶군요.
2016.09.21 – 농부: 150 그램 이상인 사과를 모두 찾고 싶군요.
2016.09.22 – 농부: 150그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요.
….
잦은 요구사항 변경
► 사과 재고 관리 프로그램
2016.09.20 – 농부: 녹색 사과를 모두 찾고 싶군요.
2016.09.21 – 농부: 150 그램 이상인 사과를 모두 찾고 싶군요.
2016.09.22 – 농부: 150그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요.
….
▬ 동작 파라미터화(Behavior Parameterization) : 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록. 나중에 실행
될 메서드의 인수로 코드 블록을 전달하는 기능.
변화하는 요구사항에 대응하기 – 1차 시도
► 첫 번째 시도 : 녹색 사과 필터링
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
변화하는 요구사항에 대응하기 – 1차 시도
► 녹색 사과 필터링
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
▬ 빨간 사과도 필터링하고 싶으면? filterRedApples?
변화하는 요구사항에 대응하기 – 2차 시도
► 두 번째 시도: 색을 파라미터화
public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)){
result.add(apple);
}
}
return result;
}
변화하는 요구사항에 대응하기 – 2차 시도
► 두 번째 시도: 색을 파라미터화
List<Apple> greenApples = filterApplesByColor(inventory, "green");
List<Apple> redApples = filterApplesByColor(inventory, "red");
변화하는 요구사항에 대응하기 – 2차 시도
► 두 번째 시도: 색을 파라미터화
List<Apple> greenApples = filterApplesByColor(inventory, "green");
List<Apple> redApples = filterApplesByColor(inventory, "red");
▬ 추가 요구사항 : 무게로 사과를 구별해야하면?
변화하는 요구사항에 대응하기 – 2차 시도
► 두 번째 시도: 색을 파라미터화 / 무게로 필터링하는 로직 추가
public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getWeight() > weight){
result.add(apple);
}
}
return result;
}
변화하는 요구사항에 대응하기 – 3차 시도
► 세 번째 시도: 가능한 모든 속성으로 필터링
public static List<Apple> filterApples(List<Apple> inventory, String color, int weight, boolean
flag){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if( (flag && apple.getColor().equals(color) ) ||
(!flag && apple.getWeight() > weight)) {
result.add(apple);
}
}
return result;
}
List<Apple> greenApples = filterApples(inventory, “green”, 0, true);
List<Apple> heavyApples = filterApples(inventory, “”, 150, false);
변화하는 요구사항에 대응하기 – 3차 시도 실패
► 세 번째 시도: 가능한 모든 속성으로 필터링 -> 실패
▬ 사과의 ‘어떤’ 속성에 기초해서 boolean 값을 반환하는 부분을 추상화하자. -> ApplePredicate
ApplePredicate
► 선택 조건에 따라 사과를 구별하는 ApplePredicate 인터페이스 정의
interface ApplePredicate{
public boolean test(Apple a);
}
static class AppleWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
}
static class AppleColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "green".equals(apple.getColor());
}
}
변화하는 요구사항에 대응하기 – 4차 시도
► 네 번째 시도: 추상적 조건으로 필터링
public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
변화하는 요구사항에 대응하기 – 4차 시도
► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기
static class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "red".equals(apple.getColor())
&& apple.getWeight() > 150;
}
}
▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다.
변화하는 요구사항에 대응하기 – 4차 시도
► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기
static class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "red".equals(apple.getColor())
&& apple.getWeight() > 150;
}
}
▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다.
▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8은 마음에 들지 않다!
변화하는 요구사항에 대응하기 – 4차 시도
► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기
static class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "red".equals(apple.getColor())
&& apple.getWeight() > 150;
}
}
▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다.
▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8은 마음에 들지 않다!
▬ 클래스를 선언과 동시에 인스턴스화 하여 코드를 줄일 수 있다. -> 익명 내부 클래스
변화하는 요구사항에 대응하기 – 5차 시도
► 다섯 번째 시도: 익명 클래스 사용
익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링
List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
public boolean test(Apple a){
return a.getColor().equals("red");
}
});
▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다.
변화하는 요구사항에 대응하기 – 5차 시도
► 다섯 번째 시도: 익명 클래스 사용
익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링
List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
public boolean test(Apple a){
return a.getColor().equals("red");
}
});
▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다.
▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드.
코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가
있다.
변화하는 요구사항에 대응하기 – 5차 시도
► 다섯 번째 시도: 익명 클래스 사용
익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링
List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
public boolean test(Apple a){
return a.getColor().equals("red");
}
});
▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다.
▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드.
코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가
있다.
▬ 람다 표현식을 이용하여 더 간단화시켜보자.
변화하는 요구사항에 대응하기 – 6차 시도
► 여섯 번째 시도: 람다 표현식 사용
List<Apple> result = filterApples(inventory, (Apple apple) ->
"red".equals(apple.getColor()));
변화하는 요구사항에 대응하기 – 정리 1
► 요구사항을 만족시키기 위한 방법 - 지표 비교
방법 요구사항 대응 코드 속성
값 파라미터화 뻣뻣함 장황함
클래스 유연함 장황함
익명 클래스 유연함 다소 장황함
람다 유연함 간결함
변화하는 요구사항에 대응하기 – 7차 시도
► 일곱 번째 시도 : 리스트 형식으로 추상화
현재 구현된 filterApples는 Apple 객체만 필터링한다. 하지만 Apple 이외의 것도 필터링을 할 수 있도록 리
스트 형식을 추상화할 수 있다.
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e : list){
if(p.test(e)){
result.add(e);
}
}
return result;
}
변화하는 요구사항에 대응하기 – 7차 시도
► 일곱 번째 시도 : 리스트 형식으로 추상화
List<Apple> redApples = filter(inventory, (Apple apple) ->
"red".equals(apple.getColor()));
List<String> evenNumbers = filter(numbers, (Integer i) -> i % 2 == 0);
동작 파라미터화 예제
► Comparator로 정렬하기
// 익명 내부 클래스
inventory.sort(new Comparator<Apple>() {
@Override
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
});
// 람다
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
동작 파라미터화 요약
1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다.
2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다.
3. 자바8에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다.
4. 기존 자바 API의 많은 메서드, 특히 정렬, 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할
수 있게 되었다.
동작 파라미터화 요약
1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다.
2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다.
3. 자바8에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다.
4. 기존 자바 API의 많은 메서드, 특히 정렬, 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할
수 있게 되었다.

More Related Content

What's hot

자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수
유진 변
 
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
해강
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
daewon jeong
 

What's hot (19)

Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기Java 8 api :: lambda 이용하기
Java 8 api :: lambda 이용하기
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)
 
JDK 변천사
JDK 변천사JDK 변천사
JDK 변천사
 
(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)
(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)
(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)
 
자바8강의 0강. java8 overview
자바8강의 0강. java8 overview자바8강의 0강. java8 overview
자바8강의 0강. java8 overview
 
자바8강의 1강. lambda expression
자바8강의 1강. lambda expression자바8강의 1강. lambda expression
자바8강의 1강. lambda expression
 
자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수
 
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
Scala 기초 (2)
Scala 기초 (2)Scala 기초 (2)
Scala 기초 (2)
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린
 
5 swift 기초함수
5 swift 기초함수5 swift 기초함수
5 swift 기초함수
 
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
[아꿈사] The C++ Programming Language 11장 연산자 오버로딩
 
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
 
Scala 기초 (4)
Scala 기초 (4)Scala 기초 (4)
Scala 기초 (4)
 
러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)러닝스칼라 - Scala 기초 (1)
러닝스칼라 - Scala 기초 (1)
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
6 swift 고급함수
6 swift 고급함수6 swift 고급함수
6 swift 고급함수
 

Similar to 동작 파라미터와 람다 In java 8

SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
Sangmin Lee
 
Programming java day2
Programming java day2Programming java day2
Programming java day2
Jaehoonyam
 

Similar to 동작 파라미터와 람다 In java 8 (9)

JavaInAction 자바 8
JavaInAction 자바 8JavaInAction 자바 8
JavaInAction 자바 8
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)
 
파이썬 기본 문법
파이썬 기본 문법파이썬 기본 문법
파이썬 기본 문법
 
Perl Script Document
Perl Script DocumentPerl Script Document
Perl Script Document
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
PySpark 배우기 Ch 06. ML 패키지 소개하기
PySpark 배우기 Ch 06. ML 패키지 소개하기PySpark 배우기 Ch 06. ML 패키지 소개하기
PySpark 배우기 Ch 06. ML 패키지 소개하기
 
Programming java day2
Programming java day2Programming java day2
Programming java day2
 
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
(IT실무교육/국비지원교육/자바/스프링교육추천)#15.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)
 
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
 

동작 파라미터와 람다 In java 8

  • 1. 동작 파라미터와 람다 - Java 8 in Action 이진우
  • 2. 진행 순서 1. 자바의 변화 배경 2. 동작 파라미터화 코드 전달하기 3. 람다 표현식
  • 3. 1. 자바의 변화 배경 프로그래밍 패러다임의 변화
  • 4. 자바의 변화 배경 1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … ) 2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화
  • 5. 자바의 변화 배경 1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … ) -> 함수형 인터페이스, 람다, 메서드 레퍼런스 2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화 -> 스트림 API
  • 6. 자바의 변화 배경 1. 함수형 프로그래밍의 약진( 스칼라, 그루비, … ) -> 함수형 인터페이스, 람다, 메서드 레퍼런스 2. 멀티코어 CPU의 등장, 어려운 멀티 스레드 동기화 -> 스트림 API
  • 7. 함수형 프로그래밍의 도입 File[] hiddenFiles = new File(".").listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isHidden(); } }); File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden());
  • 8. 함수형 프로그래밍의 도입 // 익명 내부 클래스 File[] hiddenFiles = new File(".").listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isHidden(); } }); // 람다식 File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden());
  • 9. 함수형 프로그래밍의 도입 // 익명 내부 클래스 File[] hiddenFiles = new File(".").listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isHidden(); } }); // 람다식 File[] hiddenFiles2 = new File(".").listFiles((File file)->file.isHidden()); // 메서드 레퍼런스 File[] hiddenFiles2 = new File(".").listFiles(File::isHidden);
  • 10. 녹색 사과 필터링하기 public static List<Apple> filterGreenApples(List<Apple> inventory){ List<Apple> result = new ArrayList<>(); for (Apple apple: inventory){ if ("green".equals(apple.getColor())) { result.add(apple); } } return result; }
  • 11. 무거운 사과 필터링하기 public static List<Apple> filterHeavyApples(List<Apple> inventory){ List<Apple> result = new ArrayList<>(); for (Apple apple: inventory){ if (apple.getWeight() > 150) { result.add(apple); } } return result; } ▬ if문 외에는 전부 동일, 코드의 중복 발생 -> 필터링 전략 추출
  • 12. 필터링 전략 추출 public static boolean isGreenApple(Apple apple) { return "green".equals(apple.getColor()); } public static boolean isHeavyApple(Apple apple) { return apple.getWeight() > 150; } public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p){ List<Apple> result = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ result.add(apple); } } return result; } ▬ 자바 8에 도입된 Predicate 인터페이스를 이용하면 boolean을 반환하는 함수를 담을 수 있다.
  • 13. 필터링 전략 추출 ► 한결 개선된 코드 List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple); List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple); ▬ Predicate로 메서드 레퍼런스를 담는다. Predicate p = FilteringApples::isGreenApple Predicate p = FilteringApples::isHeavyApple
  • 14. 필터링 전략 추출 ► 한결 개선된 코드 List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple); List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple); ▬ Predicate로 메서드 레퍼런스를 담는다. Predicate p = FilteringApples::isGreenApple Predicate p = FilteringApples::isHeavyApple ▬ 한두 번만 사용할 메서드를 요구사항마다 정의하는 것은 비효율. 람다를 이용해서 간단히 구현 가능. 물론 코드의 명확성을 우선시한다면 메서드 레퍼런스 활용도 바람직. List<Apple> greenApples2 = filterApples(inventory, (Apple a) -> "green".equals(a.getColor())); List<Apple> heavyApples2 = filterApples(inventory, (Apple a) -> a.getWeight() > 150); List<Apple> weirdApples = filterApples(inventory, (Apple a) -> a.getWeight() < 80 || "brown".equals(a.getColor()));
  • 15. 2. 동작 파라미터화 코드 전달하기 For. 잦은 요구사항에 대응하는 유연하고 간결한 코드 구현
  • 16. 잦은 요구사항 변경 ► 사과 재고 관리 프로그램 2016.09.20 – 농부: 녹색 사과를 모두 찾고 싶군요. 2016.09.21 – 농부: 150 그램 이상인 사과를 모두 찾고 싶군요. 2016.09.22 – 농부: 150그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요. ….
  • 17. 잦은 요구사항 변경 ► 사과 재고 관리 프로그램 2016.09.20 – 농부: 녹색 사과를 모두 찾고 싶군요. 2016.09.21 – 농부: 150 그램 이상인 사과를 모두 찾고 싶군요. 2016.09.22 – 농부: 150그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요. …. ▬ 동작 파라미터화(Behavior Parameterization) : 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록. 나중에 실행 될 메서드의 인수로 코드 블록을 전달하는 기능.
  • 18. 변화하는 요구사항에 대응하기 – 1차 시도 ► 첫 번째 시도 : 녹색 사과 필터링 public static List<Apple> filterGreenApples(List<Apple> inventory){ List<Apple> result = new ArrayList<>(); for (Apple apple: inventory){ if ("green".equals(apple.getColor())) { result.add(apple); } } return result; }
  • 19. 변화하는 요구사항에 대응하기 – 1차 시도 ► 녹색 사과 필터링 public static List<Apple> filterGreenApples(List<Apple> inventory){ List<Apple> result = new ArrayList<>(); for (Apple apple: inventory){ if ("green".equals(apple.getColor())) { result.add(apple); } } return result; } ▬ 빨간 사과도 필터링하고 싶으면? filterRedApples?
  • 20. 변화하는 요구사항에 대응하기 – 2차 시도 ► 두 번째 시도: 색을 파라미터화 public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){ List<Apple> result = new ArrayList<>(); for(Apple apple: inventory){ if(apple.getColor().equals(color)){ result.add(apple); } } return result; }
  • 21. 변화하는 요구사항에 대응하기 – 2차 시도 ► 두 번째 시도: 색을 파라미터화 List<Apple> greenApples = filterApplesByColor(inventory, "green"); List<Apple> redApples = filterApplesByColor(inventory, "red");
  • 22. 변화하는 요구사항에 대응하기 – 2차 시도 ► 두 번째 시도: 색을 파라미터화 List<Apple> greenApples = filterApplesByColor(inventory, "green"); List<Apple> redApples = filterApplesByColor(inventory, "red"); ▬ 추가 요구사항 : 무게로 사과를 구별해야하면?
  • 23. 변화하는 요구사항에 대응하기 – 2차 시도 ► 두 번째 시도: 색을 파라미터화 / 무게로 필터링하는 로직 추가 public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){ List<Apple> result = new ArrayList<>(); for(Apple apple: inventory){ if(apple.getWeight() > weight){ result.add(apple); } } return result; }
  • 24. 변화하는 요구사항에 대응하기 – 3차 시도 ► 세 번째 시도: 가능한 모든 속성으로 필터링 public static List<Apple> filterApples(List<Apple> inventory, String color, int weight, boolean flag){ List<Apple> result = new ArrayList<>(); for(Apple apple: inventory){ if( (flag && apple.getColor().equals(color) ) || (!flag && apple.getWeight() > weight)) { result.add(apple); } } return result; } List<Apple> greenApples = filterApples(inventory, “green”, 0, true); List<Apple> heavyApples = filterApples(inventory, “”, 150, false);
  • 25. 변화하는 요구사항에 대응하기 – 3차 시도 실패 ► 세 번째 시도: 가능한 모든 속성으로 필터링 -> 실패 ▬ 사과의 ‘어떤’ 속성에 기초해서 boolean 값을 반환하는 부분을 추상화하자. -> ApplePredicate
  • 26. ApplePredicate ► 선택 조건에 따라 사과를 구별하는 ApplePredicate 인터페이스 정의 interface ApplePredicate{ public boolean test(Apple a); } static class AppleWeightPredicate implements ApplePredicate{ public boolean test(Apple apple){ return apple.getWeight() > 150; } } static class AppleColorPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "green".equals(apple.getColor()); } }
  • 27. 변화하는 요구사항에 대응하기 – 4차 시도 ► 네 번째 시도: 추상적 조건으로 필터링 public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){ List<Apple> result = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ result.add(apple); } } return result; }
  • 28. 변화하는 요구사항에 대응하기 – 4차 시도 ► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기 static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; } } ▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다.
  • 29. 변화하는 요구사항에 대응하기 – 4차 시도 ► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기 static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; } } ▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다. ▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8은 마음에 들지 않다!
  • 30. 변화하는 요구사항에 대응하기 – 4차 시도 ► 네 번째 시도: 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기 static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; } } ▬ if문 동작을 파라미터화시켜서 유연함을 얻게 되었다. ▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8은 마음에 들지 않다! ▬ 클래스를 선언과 동시에 인스턴스화 하여 코드를 줄일 수 있다. -> 익명 내부 클래스
  • 31. 변화하는 요구사항에 대응하기 – 5차 시도 ► 다섯 번째 시도: 익명 클래스 사용 익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링 List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); } }); ▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다.
  • 32. 변화하는 요구사항에 대응하기 – 5차 시도 ► 다섯 번째 시도: 익명 클래스 사용 익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링 List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); } }); ▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다. ▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드. 코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가 있다.
  • 33. 변화하는 요구사항에 대응하기 – 5차 시도 ► 다섯 번째 시도: 익명 클래스 사용 익명 클래스를 이용해서 ApplePredicate를 구현하는 객체를 만드는 방법으로 필터링 List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); } }); ▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다. ▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드. 코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가 있다. ▬ 람다 표현식을 이용하여 더 간단화시켜보자.
  • 34. 변화하는 요구사항에 대응하기 – 6차 시도 ► 여섯 번째 시도: 람다 표현식 사용 List<Apple> result = filterApples(inventory, (Apple apple) -> "red".equals(apple.getColor()));
  • 35. 변화하는 요구사항에 대응하기 – 정리 1 ► 요구사항을 만족시키기 위한 방법 - 지표 비교 방법 요구사항 대응 코드 속성 값 파라미터화 뻣뻣함 장황함 클래스 유연함 장황함 익명 클래스 유연함 다소 장황함 람다 유연함 간결함
  • 36. 변화하는 요구사항에 대응하기 – 7차 시도 ► 일곱 번째 시도 : 리스트 형식으로 추상화 현재 구현된 filterApples는 Apple 객체만 필터링한다. 하지만 Apple 이외의 것도 필터링을 할 수 있도록 리 스트 형식을 추상화할 수 있다. public static <T> List<T> filter(List<T> list, Predicate<T> p){ List<T> result = new ArrayList<>(); for(T e : list){ if(p.test(e)){ result.add(e); } } return result; }
  • 37. 변화하는 요구사항에 대응하기 – 7차 시도 ► 일곱 번째 시도 : 리스트 형식으로 추상화 List<Apple> redApples = filter(inventory, (Apple apple) -> "red".equals(apple.getColor())); List<String> evenNumbers = filter(numbers, (Integer i) -> i % 2 == 0);
  • 38. 동작 파라미터화 예제 ► Comparator로 정렬하기 // 익명 내부 클래스 inventory.sort(new Comparator<Apple>() { @Override public int compare(Apple a1, Apple a2) { return a1.getWeight().compareTo(a2.getWeight()); } }); // 람다 inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
  • 39. 동작 파라미터화 요약 1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다. 2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다. 3. 자바8에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다. 4. 기존 자바 API의 많은 메서드, 특히 정렬, 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할 수 있게 되었다.
  • 40. 동작 파라미터화 요약 1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다. 2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다. 3. 자바8에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다. 4. 기존 자바 API의 많은 메서드, 특히 정렬, 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할 수 있게 되었다.

Editor's Notes

  1. 이 ppt는 1시간 발표를 위해 제작. 람다 표현식 자체도 분량이 많기 때문에 추가 ppt를 발표 진행
  2. 자바가 변화된 배경 설명
  3. 자바 8이 나오게 된 배경으로는 2가지 정도가 있다고 말할 수 있습니다. 스칼라 그루비는 JVM과 바이트코드에 좀더 최적화된 언어 함수형 프로그래밍은 프로그래머의 생각을 그대로 적는 것이 번거롭지 않고 편해서 자주 쓰이는 추세( 객체지향 언어보다 더 강력한 추상화 제공 )
  4. 물론 이번 ppt에는 스트림 API는 생략하겠습니다.
  5. 자바 역사를 통틀어 가장 큰 변화가 자바8에서 나타났는데 함수형 프로그래밍의 도입이라고 할 수 있다.
  6. 기존 익명 내부 클래스 vs 새로운 람다식의 차이 익명 내부 클래스를 이용하게 되면, 단 세 행의 코드지만 굳이 저렇게 compareTo를 감싸고, Comparator를 인스턴스화해야하나 라는 것이 마음에 들지 않습니다. 아래 람다식으롣 동일한 기능을 구현할 수 있는데, 단 한 줄만으로 같은 기능을 구현할 수 있습니다.
  7. 이미 차이가 있지만, 기존의 메서드를 이용하여 코드 길이를 줄일 수도 있는 메서드 레퍼런스 기능을 이용할 수도 있습니다.
  8. 굵은 라인 녹색 사과만 선택
  9. 굵은 라인 무거운 사과만 선택 소프트웨어공학적인 측면에서 복사 붙여넣기의 단점은 확실하다. 두 코드의 기능이 다르고, 코드가 한 줄씩 다르다.
  10. 변화는 부분을 추상화하여 사과 필터링 전략 추출, 이 때의 Predicate<T> p가 등장하는데, 람다처럼 수학에서 온 용어입니다. 수학에서는 인수로 값을 받아 true나 false를 반환하는 함수를 프레디케이트라고 합니다. 자바 8에서는 Predicate 인터페이스를 지원합니다.
  11. Predicate 인터페이스를 활용하여 사과를 filtering하는 로직 구현
  12. 그렇지만 한 두번만 사용할 메서드를 매 요구사항마다 정의하는 것도 자바8은 비효율이라고 생각합니다. 람다를 사용하면 번거로운 함수 정의 없이 사용 가능합니다. 물론 람다가 몇 줄 이상으로 길어진다면, 익명 람다보다는 코드가 수행하는 일을 잘 설명하는 이름을 가진 메서드를 정의하고 메서드 레퍼런스를 활용하는 것이 바람직합니다. 코드의 명확성이 제일 중요합니다. 그러면 람다, 메서드 레퍼런스 등의 기능을 포괄하는 개념인 ‘동작 파라미터화’에 대해 알아보겠습니다.
  13. 동작파라미터화 코드 전달을 하여, 보다 잦은 요구사항에 대응하는 유연하고 간결한 코드 구현을 할 수 있습니다. 그럼 동작파라미터화에 대해 알아보겠습니다.
  14. 이렇게 시시각각 변하는 사용자 요구사항에 대응하려면 어떻게 해야할까요? 유지보수가 쉽게 코딩을 해야합니다.
  15. 자주 바뀌는 요구사항은 동작파라미터화로 해결할 수 있다. 동작 파라미터화의 유용성은 예시를 들면서 설명하겠습니다.
  16. 별 문제 없이 잘 돌아가는 코드
  17. 옅은 녹색, 어두운 빨간색, 노란색도 필터링하려면? 이런 상황에서는 추상화를 해야한다. “비슷한 코드를 구현한 다음에 추상화하라.”
  18. 색을 파라미터화할 수 있도록 메서드에 파라미터를 추가하면, 변화하는 요구사항에 좀더 유연하게 대응하는 코드를 만들 수 있다.
  19. 색상에 대해서는 유연한 코드 구현 성공
  20. 유연한 코드 구현, 하지만 색 이외에도 무게로도 구별해야 하면?
  21. 좋은 해결책이지만 기존 색으로 구별하는 코드와 if문 빼고는 대부분 중복 -> 소프트웨어 공학의 DRY(don’t repeat yourself) 원칙을 어기는 것 색과 무게를 함께 filtering 하는 로직을 추가하게 되면, flag를 추가해야한다. (클릭)
  22. 암걸리는 코드.. 0. 파라미터에 값 넣는 것이 헷갈린다. 속성이 추가 되면 if문이 복잡해짐 속성간 조합이 생겨도 if문이 복잡해짐 거대한 필터 메서드가 되버리고 만다. 문제가 잘 정의되어있고 요구사항이 추가 될 일이 적으면 이 방법도 나쁘진 않습니다. 하지만 코드의 가독성을 올릴 수 있는 방법이 있으니, 동작 파라미터화를 이용하여 유연성을 얻는 방법이 있습니다.
  23. 코드가 복잡해지면 추상화 포인트를 찾아봐야 한다. 코드를 곰곰히 보면 ‘if문’을 제외한 부분들은 변화되지 않으므로, if문에 들어가는 동작을 추상화하면 된다. Predicate는 수학에서 쓰이는 용어로, 찬반형 함수, 즉 true or false를 반환하는 함수이다.
  24. Predicate 메서드에 따라, filter 메서드의 동작이 달라진다. 이를 ‘전략 패턴’이라고 하는데, 전략 패턴은 각 알고리즘을 캡슐화하는 인터페이스를 정의한 다음, 런타임에 그 구현체를 선택하는 기법이다. ApplePredicate 인터페이스를 filterApples 메서드에 어떻게 적용할 수 있을까요? Filter에서 ApplePredicate 객체를 받아 조건을 검사하도록 메서드를 고쳐야 하는데, 이것이 동작 파라미터화입니다.
  25. 요구사항 대응에 유연하고 가독성 좋은 코드 완성, 만약 무거운 빨간 사과를 필터링해야한다면?
  26. filterApples 메서드에 새로운 동작을 전달하려면 Predicate를 더 추가해야 한다. 즉 추가로 클래스를 정의하고 인스턴스화 해야하는데, 자바8은 이를 번거롭게 생각한다.
  27. 코드 전체 통틀어서 한 곳에서만 사용되는 Predicate를 줄일 수 있는 방법이 있다. -> 익명 클래스 익명내부클래스는 필요할 때 즉석에서 구현해서 만드는 클래스이다. ( 자바8 GUI나 안드로이드 리스너 등에서 흔히 사용 )
  28. 유연성과 간결함을 모두 잡을 수 있고 여러 타입에 써먹을 수 있는 filter 메서드를 만들게 되었다.
  29. 람다를 이용하면 코드를 이렇게 간단화시킬 수 있다.
  30. 람다를 이용하면 코드를 이렇게 간단화시킬 수 있다.
  31. 람다를 이용하면 코드를 이렇게 간단화시킬 수 있다.