40
동동 동동동동동 동동 - Java 8 in Action 동동동

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

  • Upload
    -

  • View
    249

  • Download
    4

Embed Size (px)

Citation preview

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

동작 파라미터와 람다 - Java 8 in Action

이진우

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

진행 순서1. 자바의 변화 배경2. 동작 파라미터화 코드 전달하기3. 람다 표현식

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

1. 자바의 변화 배경

프로그래밍 패러다임의 변화

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

자바의 변화 배경1. 함수형 프로그래밍의 약진 ( 스칼라 , 그루비 , … )2. 멀티코어 CPU 의 등장 , 어려운 멀티 스레드 동기화

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

자바의 변화 배경1. 함수형 프로그래밍의 약진 ( 스칼라 , 그루비 , … ) -> 함수형 인터페이스 , 람다 , 메서드 레퍼런스 2. 멀티코어 CPU 의 등장 , 어려운 멀티 스레드 동기화 -> 스트림 API

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

자바의 변화 배경1. 함수형 프로그래밍의 약진 ( 스칼라 , 그루비 , … ) -> 함수형 인터페이스 , 람다 , 메서드 레퍼런스 2. 멀티코어 CPU 의 등장 , 어려운 멀티 스레드 동기화 -> 스트림 API

Page 7: 동작 파라미터와 람다 In java 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());

Page 8: 동작 파라미터와 람다 In java 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());

Page 9: 동작 파라미터와 람다 In java 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());

// 메서드 레퍼런스File[] hiddenFiles2 = new File(".").listFiles(File::isHidden);

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

녹색 사과 필터링하기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;}

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

무거운 사과 필터링하기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 문 외에는 전부 동일 , 코드의 중복 발생 -> 필터링 전략 추출

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

필터링 전략 추출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 을 반환하는 함수를 담을 수 있다 .

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

필터링 전략 추출 ► 한결 개선된 코드

List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple);List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);

▬ Predicate 로 메서드 레퍼런스를 담는다 .Predicate p = FilteringApples::isGreenApplePredicate p = FilteringApples::isHeavyApple

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

필터링 전략 추출 ► 한결 개선된 코드

List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple);List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);

▬ Predicate 로 메서드 레퍼런스를 담는다 .Predicate p = FilteringApples::isGreenApplePredicate 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()));

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

2. 동작 파라미터화 코드 전달하기

For. 잦은 요구사항에 대응하는 유연하고 간결한 코드 구현

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

잦은 요구사항 변경 ► 사과 재고 관리 프로그램

2016.09.20 – 농부 : 녹색 사과를 모두 찾고 싶군요 .2016.09.21 – 농부 : 150 그램 이상인 사과를 모두 찾고 싶군요 .2016.09.22 – 농부 : 150 그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요 .….

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

잦은 요구사항 변경 ► 사과 재고 관리 프로그램

2016.09.20 – 농부 : 녹색 사과를 모두 찾고 싶군요 .2016.09.21 – 농부 : 150 그램 이상인 사과를 모두 찾고 싶군요 .2016.09.22 – 농부 : 150 그램 이상이면서 녹색인 사과를 모두 찾을 수 있으면 좋겠네요 .….

▬ 동작 파라미터화 (Behavior Parameterization) : 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록 . 나중에 실행될 메서드의 인수로 코드 블록을 전달하는 기능 .

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

변화하는 요구사항에 대응하기 – 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; }

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

변화하는 요구사항에 대응하기 – 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?

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

변화하는 요구사항에 대응하기 – 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;}

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

변화하는 요구사항에 대응하기 – 2 차 시도 ► 두 번째 시도 : 색을 파라미터화

List<Apple> greenApples = filterApplesByColor(inventory, "green");List<Apple> redApples = filterApplesByColor(inventory, "red");

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

변화하는 요구사항에 대응하기 – 2 차 시도 ► 두 번째 시도 : 색을 파라미터화

List<Apple> greenApples = filterApplesByColor(inventory, "green");List<Apple> redApples = filterApplesByColor(inventory, "red");

▬ 추가 요구사항 : 무게로 사과를 구별해야하면 ?

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

변화하는 요구사항에 대응하기 – 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;}

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

변화하는 요구사항에 대응하기 – 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);

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

변화하는 요구사항에 대응하기 – 3 차 시도 실패 ► 세 번째 시도 : 가능한 모든 속성으로 필터링 -> 실패 ▬ 사과의 ‘어떤’ 속성에 기초해서 boolean 값을 반환하는 부분을 추상화하자 . -> ApplePredicate

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

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()); }}

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

변화하는 요구사항에 대응하기 – 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;}

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

변화하는 요구사항에 대응하기 – 4 차 시도 ► 네 번째 시도 : 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기

static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; }}

▬ if 문 동작을 파라미터화시켜서 유연함을 얻게 되었다 .

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

변화하는 요구사항에 대응하기 – 4 차 시도 ► 네 번째 시도 : 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기

static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; }}

▬ if 문 동작을 파라미터화시켜서 유연함을 얻게 되었다 .

▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8 은 마음에 들지 않다 !

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

변화하는 요구사항에 대응하기 – 4 차 시도 ► 네 번째 시도 : 추상적 조건으로 필터링 : 빨갛고 무거운 사과 구별하기

static class AppleRedAndHeavyPredicate implements ApplePredicate{ public boolean test(Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; }}

▬ if 문 동작을 파라미터화시켜서 유연함을 얻게 되었다 .

▬ 하지만 여러 클래스를 구현해서 인스턴스화하는 과정도 자바 8 은 마음에 들지 않다 !

▬ 클래스를 선언과 동시에 인스턴스화 하여 코드를 줄일 수 있다 . -> 익명 내부 클래스

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

변화하는 요구사항에 대응하기 – 5 차 시도 ► 다섯 번째 시도 : 익명 클래스 사용

익명 클래스를 이용해서 ApplePredicate 를 구현하는 객체를 만드는 방법으로 필터링List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); }});

▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다 .

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

변화하는 요구사항에 대응하기 – 5 차 시도 ► 다섯 번째 시도 : 익명 클래스 사용

익명 클래스를 이용해서 ApplePredicate 를 구현하는 객체를 만드는 방법으로 필터링List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); }});

▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다 .

▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드 .코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가 있다 .

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

변화하는 요구사항에 대응하기 – 5 차 시도 ► 다섯 번째 시도 : 익명 클래스 사용

익명 클래스를 이용해서 ApplePredicate 를 구현하는 객체를 만드는 방법으로 필터링List<Apple> redApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); }});

▬ 선언과 동시에 인스턴스화하니 복잡한 코드를 줄일 수 있는 장점이 있다 .

▬ 하지만 블록지정된 부분들은 앞으로도 계속 중복되어 코드 라인을 차지하게 될 코드 .코드를 전달하는 과정에서 결국 객체를 만들고 명시적으로 새로운 동작을 정의하는 메서드를 구현해야 하는 문제가 있다 .

▬ 람다 표현식을 이용하여 더 간단화시켜보자 .

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

변화하는 요구사항에 대응하기 – 6 차 시도 ► 여섯 번째 시도 : 람다 표현식 사용

List<Apple> result = filterApples(inventory, (Apple apple) -> "red".equals(apple.getColor()));

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

변화하는 요구사항에 대응하기 – 정리 1

► 요구사항을 만족시키기 위한 방법 - 지표 비교방법 요구사항 대응 코드 속성값 파라미터화 뻣뻣함 장황함클래스 유연함 장황함익명 클래스 유연함 다소 장황함람다 유연함 간결함

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

변화하는 요구사항에 대응하기 – 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;}

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

변화하는 요구사항에 대응하기 – 7 차 시도 ► 일곱 번째 시도 : 리스트 형식으로 추상화

List<Apple> redApples = filter(inventory, (Apple apple) -> "red".equals(apple.getColor()));

List<String> evenNumbers = filter(numbers, (Integer i) -> i % 2 == 0);

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

동작 파라미터화 예제► 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()));

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

동작 파라미터화 요약1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다 .2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다 .3. 자바 8 에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다 .4. 기존 자바 API 의 많은 메서드 , 특히 정렬 , 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할 수 있게 되었다 .

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

동작 파라미터화 요약1. 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다 .2. 변화하는 요구사항에 더욱 유연하고 간결하게 대응할 수 있는 코드를 구현할 수 있다 .3. 자바 8 에서는 람다를 이용하여 코드의 장황함을 대폭 줄일 수 있다 .4. 기존 자바 API 의 많은 메서드 , 특히 정렬 , 스레드 그리고 GUI 처리에 대한 다양한 동작을 파라미터화 할 수 있게 되었다 .