SlideShare a Scribd company logo
나에 첫번째 자바8 람다식
- @blueiur(twitter)
오! 벌써 새벽
3시네, 컴퓨
터 끄고 자야
겠어!
한 시간 후 ...
정대원@blueiur(twitter)
● like ..
○ programming language
○ functionl programming
○ elixir
○ scala
○ ruby
람다
● 람다 계산법
● 익명 함수
● 함수 리터럴
● 클로저
익명 함수
Wikipedia
● 특정 식별자 없이 정의되거나 호출될 수 있는 함수
람다가 왜 필요할가?
● 행위 매개변수(코드 블럭) 전달
// 1. 컬렉션 정렬 (익명 클래스 사용)
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
컬렉션 정렬 - 익명 클래스 사용
// 1. 컬렉션 정렬 (익명 클래스 사용)
Collections.sort(names, ...);
Collections.sort + a.compareTo(b)
new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
}
// 1. 컬렉션 정렬 (익명 클래스 사용)
Collections.sort(names, ...);
Collections.sort + [a.compareTo(b), b.compareTo(a)]
new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
}
new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
}
새 쓰레드 생성 - 익명 클래스 사용
// 쓰레드 생성 (익명 클래스 사용)
new Thread(new Runnable() {
@Override public void run() {
System.out.println("I consume memory, therefore i am!"); }
}).start();
// 1. 쓰레드 생성 (익명 클래스 사용)
new Thread(...);
new Thread(...) + System.out.println("...");
new Thread(new Runnable() {
@Override public void run() {
System.out.println("I consume memory, therefore i am!"); }
}).start();
// 1. 쓰레드 생성 (익명 클래스 사용)
new Thread(...);
new Thread(...) + [System.out.println("..."), DB.write("...")]
new Thread(new Runnable() {
@Override public void run() {
System.out.println("I consume memory, therefore i am!"); }
}).start();
new Thread(new Runnable() {
@Override public void run() {
DB.write("I consume memory, therefore i am!"); }
}).start();
행위 매개변수 사용에 장점
● 고정된 코드 + 행위 매개변수(익명 클래스) 조합을 사용한 다양한 확장
a. 더 일반화된 메서드
b. 더 유연한 인터페이스
c. 코드 중복 제거
요구사항 - 리스트 정렬
● 정수형 리스트 정렬
● 문자열 리스트 정렬
● comparable을 상속받지 않은 객체 정렬
a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
ArrayList<T> ls = new ArrayList<>(list);
for(int i=0; i<ls.size(); i++) {
int minIndex = i;
for(int j=i+1; j<ls.size(); j++) {
if (ls.get(j).compareTo(ls.get(minIndex)) < 0) {
minIndex = j;
}
}
T tmp = ls.get(i);
ls.set(i, ls.get(minIndex));
ls.set(minIndex, tmp);
}
return ls;
}
sort(Arrays.asList("c", "b", "d", "a"))
sort(Arrays.asList(1, 3, 2, 4))
Generic을 사용한 정렬 구현
comparable을 상속
요구사항 - 리스트 정렬
● 정수형 리스트 정렬
● 문자열 리스트 정렬
● comparable을 상속받지 않은 객체 정렬
a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
정렬 기준을 변경하고 싶다
sort(Arrays.asList(k7, k5, k3, i30), 가격 순으로 정렬)
sort(Arrays.asList(k7, k5, k3, i30), 이름 순으로 정렬)
public class Car {
public String name;
public int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
}
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
ArrayList<T> ls = new ArrayList<>(list);
for(int i=0; i<ls.size(); i++) {
int minIndex = i;
for(int j=i+1; j<ls.size(); j++) {
if (ls.get(j).compareTo(ls.get(minIndex)) < 0) {
minIndex = j;
}
}
T tmp = ls.get(i);
ls.set(i, ls.get(minIndex));
ls.set(minIndex, tmp);
}
return ls;
}
코드 분석
값 2개를 비교해서
[-1, 0, 1]중 하나를 반환
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
ArrayList<T> ls = new ArrayList<>(list);
for(int i=0; i<ls.size(); i++) {
int minIndex = i;
for(int j=i+1; j<ls.size(); j++) {
if (ls.get(j).compareTo(ls.get(minIndex)) < 0) {
minIndex = j;
}
}
T tmp = ls.get(i);
ls.set(i, ls.get(minIndex));
ls.set(minIndex, tmp);
}
return ls;
}
인터페이스로 분리
interface Comparator<T> {
int compare(T a, T b);
}
값 2개를 비교해서
[-1, 0, 1]중 하나를 반환
public static <T> List<T> sort(List<T> list, Comparator<T> comp) {
ArrayList<T> ls = new ArrayList<>(list);
for(int i=0; i<ls.size(); i++) {
int minIndex = i;
for(int j=i+1; j<ls.size(); j++) {
if (comp.compare(ls.get(j),ls.get(minIndex) < 0) {
minIndex = j;
}
}
T tmp = ls.get(i);
ls.set(i, ls.get(minIndex));
ls.set(minIndex, tmp);
}
return ls;
}
Comparator 인터페이스를 사용
interface Comparator<T> {
int compare(T a, T b);
}
값 2개를 비교해서
[-1, 0, 1]중 하나를 반환
// 2. 이름으로 정렬
sort(cars, new Comparator<Car>() {
@Override public int compare(Car a, Car b) {
return a.name.compareTo(b.name);
}
});
익명 클래스를 사용한 행동 전달
// 1. 가격으로 정렬
sort(cars, new Comparator<Car>() {
@Override public int compare(Car a, Car b) {
return a.price.compareTo(b.price);
}
});
다른 부분
가격/이름 으로 비교
요구사항 - 리스트 정렬
● 정수형 리스트 정렬
● 문자열 리스트 정렬
● comparable을 상속받지 않은 객체 정렬
a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
행위 매개변수 사용에 장점
● 고정된 코드 + 행위 매개변수(코드 블럭) 조합을 사용한 다양한 확장
a. 더 일반화된 메서드
b. 더 유연한 인터페이스
c. 코드 중복 제거
람다가 왜 필요할가?
● 행위 매개변수(코드 블럭) 전달
● 자바8 이전에는 익명 클래스를 사용
익명 함수
Wikipedia
● 특정 식별자 없이 정의되거나 호출될 수 있는 함수
● 자바에 함수가 있나? -> 람다!
(인자 목록) -> { 구문 }
● x -> x + 1
● (x) -> x + 1
● (int x) -> x + 1
● (int x, int y) -> x + y
● (x, y) -> { System.out.println(x + y) }
● () -> { System.out.println("runnable!"); }
람다 문법
@Functional Interface
● 추상 메서드가 1개 뿐인 인터페이스
● 인터페이스를 함수처럼 사용하자
@FunctionalInterface
interface Action {
void run(String param);
void stop(String param);
}
@FunctionalInterface
interface Runnable() {
void run();
}
메서드 1개 OK!
메서드 2개 NO!
익명 클래스를 람다로 변환해 주는 IntelliJ
// 1. 람다 사용 (자바8)
Collections.sort(names, (a, b) -> a.compareTo(b));
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
행위 매개변수 전달: 클래스 -> 람다
1:1 대응
interface Comparator<T> {
int compare(T a, T b);
}
함수형 인터페이스를 사용한 정렬
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
interface Comparator<T> {
int compare(T a, T b);
}
불필요한 객체 생성 제거, 메서드도 1개뿐이니 별도 이름 불필요
객체 이름 제거
메서드 이름 제거
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
interface Comparator<T> {
int compare(T a, T b);
}
반환 타입과 파라미터 타입도 이미 정해져 있으니 제거
객체 이름 제거
메서드 이름 제거
반환 값 및 파라미터 타입 추론
// 1. 람다 사용 (자바8)
Collections.sort(names, (a, b) -> { return a.compareTo(b); });
비슷하다
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
람다 문법: (인자 목록) -> { 구문 }
● x -> {return x * 2}
● x -> x * 2
● (int x) -> x + 1
● (int x, int y) -> x + y
● (x, y) -> { System.out.println(x + y) }
● () -> { System.out.println("runnable!"); }
실행문이 1개인 경우 {} 와
return 키워드 생략 가능
// 1. 람다 사용 (자바8)
Collections.sort(names, (a, b) -> a.compareTo(b));
익명 클래스 -> 람다
// 1. 익명 클래스 사용 (자바8 이전)
Collections.sort(names, new Comparator<String>() {
@Override public int compare(String a, String b) {
return a.compareTo(b);
}
});
@FunctionalInterface
interface Adder {
int add(int a, int b);
}
????? func = (int a, int b) -> { return a + b };
????? shortFunc = (a, b) -> a + b;
람다 타입
@FunctionalInterface
interface Adder {
int add(int a, int b);
}
Adder func = (int a, int b) -> { return a + b };
Adder shortFunc = (a, b) -> a + b;
람다 타입
Q: 람다는 단순히 익명 클래스에 문법 치환인가?
A: No! 실제로는 익명 클래스에 비효율을 제거하기 위해서 사용
invoke dynamic
interface Comparator<T> {
int compare(T a, T b);
}
함수형 인터페이스 - 추상 메서드를 1개만 들고 있다
@FunctionalInterface
interface Runnable<T> {
void run();
}
???
@FunctionalInterface 어노테이션은 붙이는 이유?
● 컴파일러가 추상 메서드가 2개인 경우 컴파일 오류 발생
● Javadoc에 @FunctionalInterface 글 추가
Target typing
● 람다 -> 익명 클래스 변환시 가장 유사한 타입을 찾아가는것
public static <X, Y> void processElements(
Iterable<X> source,
Predicate<X> tester,
Function <X, Y> mapper,
Consumer<Y> block) {
for (X p : source) {
if (tester.test(p)) {
Y data = mapper.apply(p);
block.accept(data);
}
}
}
Target typing
processElements(
roster,
p -> p.getGender() == Person.Sex.MALE // Predicate
p -> p.getEmailAddress(), // Function
email -> System.out.println(email) // Consumer
);
람다 두개 모두 같은 모습이지만
알아서 잘 찾아간다
Target typing and Method arguments
predicate가 왜 필요할가?
Function<String, Boolean> isDaewon = s -> "daewon".equals(s);
Predicate<String> isDaewon = s -> "daewon".equals(s);
Target typing and Method arguments
interface Runnable {
void run();
}
interface Callable<V> {
V call();
}
void invoke(Runnable r) {
r.run();
}
<T> T invoke(Callable<T> c) {
return c.call();
}
invoke(() -> {});
invoke(() -> "done");
Target typing and Method arguments
interface Runnable {
void run();
}
interface Callable<V> {
V call();
}
void invoke(Runnable r) {
r.run();
}
<T> T invoke(Callable<T> c) {
return c.call();
}
invoke(() -> {});
invoke(() -> "done");
반환값을 참고해서
오버로드된 메서드도 잘 찾아간다
변수 포획
public static void thread(String msg) {
int tmp = 10;
new Thread( () -> System.out.println(msg) ).start();
}
람다 내부에 선언되지 않은 변수를 참조할 수 있다
● 자유변수: 나를 감싸고 있는 유효 범위 변수
a. String msg, int tmp
자신은 감싸고 있는 유효 범위 변수에 접근 가능
public static void thread(String msg) {
new Thread( () -> {
msg = "must be final";
System.out.println(msg) ).start();
}
}
컴파일 에러: 포획된 변수를 수정
포획된 변수는 언제나 final이여야 한다
Function<String, Predicate<String>> startsWithFactory = s1 -> {
return (s2) -> s2.indexOf(s1) > -1;
};
Predicate<String> isIncludeGoogle = startsWithFactory.apply("google");
Predicate<String> isIncludeApple = startsWithFactory.apply("apple");
System.out.println(isIncludeApple.test("microsoft.com apple.com")); // true
System.out.println(isIncludeGoogle.test("microsoft.com apple.com")); // false
변수 참조를 활용해서 동적으로 새로운 람다를 생성하는 람다
자신은 감싸고 있는 유효 범위 변수에 접근 가능
미리 정의된 함수형 인터페이스
● 람다를 사용하려면 항상 인터페이스를 필요할가?
● 람다 사용시 새로운 인터페이스를 매번 만들어야 하나?
미리 정의된 함수형 인터페이스
● 람다를 사용하려면 항상 인터페이스를 필요할가? - yes
● 람다 사용시 새로운 인터페이스를 매번 만들어야 하나? - no(반만 yes)
Car price price > 3000 sum
cars.stream().map(c -> c.gerPrice()).filter(p -> p > 3000).reduce((a, b) -> a + b));
람다를 위해 3개 인터페이스 필요
interface Function interface Predicate interface BinaryOperator
미리 정의된 함수형 인터페이스
IntPredicate
IntSupplier
IntToDoubleFunction
IntToLongFunction
IntUnaryOperator
LongBinaryOperator
LongConsumer
LongFunction<R>
LongPredicate
LongSupplier
LongToDoubleFunction
LongToIntFunction
LongUnaryOperator
ObjDoubleConsumer<T>
ObjIntConsumer<T>
ObjLongConsumer<T>
Predicate<T>
Supplier<T>
BiConsumer<T,U>
BiFunction<T,U,R>
BinaryOperator<T>
BiPredicate<T,U>
BooleanSupplier
Consumer<T>
DoubleBinaryOperator
DoubleConsumer
DoubleFunction<R>
DoublePredicate
DoubleSupplier
DoubleToIntFunction
DoubleToLongFunction
DoubleUnaryOperator
Function<T,R>
IntBinaryOperator
IntConsumer
IntFunction<R>
지연 연산
// 디버그 모드에서만 실행
public void debug(String message) {
if (log.isDebugEnabled()) {
log.log(message);
}
}
debug(some.expensive("operation"));
디버그 모드에서만 동작하는 함수
디버그 모드에서는 동작
// 디버그 모드에서만 실행
public void debug(String message) {
if (log.isDebugEnabled()) {
log.log(message);
}
}
debug(some.expensive("operation"));
평가 시점
함수 인자는 호출 시점에 평가가 된다
// 디버그 모드에서만 실행
public void debug(Consumer<String> consumer) {
if (log.isDebugEnabled()) {
log.log(consumer.accept());
}
}
debug(() -> some.expensive("operation"));
람다로 평가 시점 조절
람다를 사용해서 평가를 뒤로 미룬다
// 람다가 없는 경우
debug(some.expensive("operation"));
// 람다 사용
debug(() -> some.expensive("operation"));
호출 하는 쪽이 조금 불편해 졌다
문제 다시 보기
● 빌려쓰기 패턴
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
파일을 한 라인씩 읽어서 STDOUT으로 출력
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
DB.write(line);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
파일을 한 라인씩 읽어서 DB에 저장
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// 이 부분 외 모두 중복!
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
중복 발생!
DB.write(line);
System.out.println(line);
현재 라인으로 무엇인가를 처리
public void withFile(String fileName) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(filename));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// 이 부분 외 모두 중복!
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null)
bufferedReader.close();
}
}
중복 발생!
interface Consumer<T> {
void accept(T a);
}
DB.write(line);
System.out.println(line);
어떤 값을 받아서 소비한다.
interface Consumer<T> {
void accept(T a);
}
각 라인을 인자로 넘겨 받아서 소비한다 public void accept(String line) {
System.out.println(line);
}
class DBWorker class PrintWorker class DBAndPrintWorker
interface Consumer
클래스로 구현
interface Consumer<T> {
void accept(T a);
}
class DBWorker implements Consumer<String> {
public void accept(String line) {
db.store(line);
}
}
class PrintWorker implements Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
};
class DBAndPrintWorker implements Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
};
withFile("input.txt", new DBWorker());
withFile("input.txt", new PrintWorker());
withFile("input.txt", new DBAndPrintWorker());
다양한 종류에 클래스 구현
interface Consumer<T> {
void accept(T a);
}
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
});
익명 클래스 사용
interface Consumer<T> {
void accept(T a);
}
메서드 딱 1개!
함수형 인터페이스
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
});
interface Consumer<T> {
void accept(T a);
}
익명 클래스 사용
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
});
interface Consumer<T> {
void accept(T a);
}
중복되는 객체 이름 제거
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
});
interface Consumer<T> {
void accept(T a);
}
중복되는 메서드 이름 제거
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
});
withFile("input.txt", new Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
});
interface Consumer<T> {
void accept(T a);
}
실제로 다른 부분은 함수 본체
interface Consumer<T> {
void accept(T a);
}
람다 사용
withFile("input.txt", line -> db.store);
withFile("input.txt", line -> System.out.println);
withFile("input.txt", line -> {
db.store(line);
System.out.println(line);
});
interface Consumer<T> {
void accept(T a);
}
class DBWorker implements Consumer<String> {
public void accept(String line) {
db.store(line);
}
}
class PrintWorker implements Consumer<String> {
public void accept(String line) {
System.out.println(line);
}
};
class DBAndPrintWorker implements Consumer<String> {
public void accept(String line) {
db.store(line);
System.out.println(line);
}
};
// 클래스 사용
withFile("input.txt", new DBWorker());
withFile("input.txt", new PrintWorker());
withFile("input.txt", new DBAndPrintWorker());
불필요 코드가 많이 사라짐
// 람다 사용
withFile("input.txt", line -> db.store);
withFile("input.txt", line -> System.out.println);
withFile("input.txt", line -> {
db.store(line);
System.out.println(line);
});
감사합니다.
- @blueiur(twitter)

More Related Content

What's hot

이것이 자바다 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
 
JDK 변천사
JDK 변천사JDK 변천사
JDK 변천사
SeungHyun Eom
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법
Terry Cho
 
Java8 & Lambda
Java8 & LambdaJava8 & Lambda
Java8 & Lambda
기현 황
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8Sangmin Lee
 
R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1
happychallenge
 
Just java
Just javaJust java
Just java
Jong Wook Kim
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
Jong Woo Rhee
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조
영기 김
 
R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작
Terry Cho
 
R 기본-데이타형 소개
R 기본-데이타형 소개R 기본-데이타형 소개
R 기본-데이타형 소개
Terry Cho
 
Python+numpy pandas 2편
Python+numpy pandas 2편Python+numpy pandas 2편
Python+numpy pandas 2편
Yong Joon Moon
 
R 기초 : R Basics
R 기초 : R BasicsR 기초 : R Basics
R 기초 : R Basics
Yoonwhan Lee
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
MIN SEOK KOO
 
파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229
Yong Joon Moon
 
(Lisp)
(Lisp)(Lisp)
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API
Arawn Park
 
Lambda 란 무엇인가
Lambda 란 무엇인가Lambda 란 무엇인가
Lambda 란 무엇인가
Vong Sik Kong
 

What's hot (19)

이것이 자바다 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 변천사
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법
 
Java8 & Lambda
Java8 & LambdaJava8 & Lambda
Java8 & Lambda
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1
 
Just java
Just javaJust java
Just java
 
강의자료4
강의자료4강의자료4
강의자료4
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조
 
R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작
 
R 기본-데이타형 소개
R 기본-데이타형 소개R 기본-데이타형 소개
R 기본-데이타형 소개
 
Python+numpy pandas 2편
Python+numpy pandas 2편Python+numpy pandas 2편
Python+numpy pandas 2편
 
R 기초 : R Basics
R 기초 : R BasicsR 기초 : R Basics
R 기초 : R Basics
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229
 
(Lisp)
(Lisp)(Lisp)
(Lisp)
 
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API
 
Lambda 란 무엇인가
Lambda 란 무엇인가Lambda 란 무엇인가
Lambda 란 무엇인가
 

Similar to 2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)

함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
HyeonSeok Choi
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
JiandSon
 
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
Donghyeok Kang
 
4. stack
4. stack4. stack
4. stack
Geunhyung Kim
 
Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, Scalability
Dongwook Lee
 
파이썬 스터디 2주차
파이썬 스터디 2주차파이썬 스터디 2주차
파이썬 스터디 2주차
Han Sung Kim
 
Java stream v0.1
Java stream v0.1Java stream v0.1
Java stream v0.1
Hyosang Hong
 
Java stream v0.1
Java stream v0.1Java stream v0.1
Java stream v0.1
Hyosang Hong
 
Hacosa js study 7th
Hacosa js study 7thHacosa js study 7th
Hacosa js study 7th
Seong Bong Ji
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
Young-Beom Rhee
 
Functional programming
Functional programmingFunctional programming
Functional programming
ssuserdcfefa
 
파이썬 기본 문법
파이썬 기본 문법파이썬 기본 문법
파이썬 기본 문법
SeongHyun Ahn
 
Data Mining with R CH1 요약
Data Mining with R CH1 요약Data Mining with R CH1 요약
Data Mining with R CH1 요약
Sung Yub Kim
 
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
S.O.P.T - Shout Our Passion Together
 
파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304
Yong Joon Moon
 
R을 이용한 데이터 분석
R을 이용한 데이터 분석R을 이용한 데이터 분석
R을 이용한 데이터 분석
simon park
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initialization
Eunjoo Im
 

Similar to 2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원) (20)

함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 자바8 람다 나머지 이야기 (박성철)
 
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
 
4. stack
4. stack4. stack
4. stack
 
Scalability
ScalabilityScalability
Scalability
 
Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, Scalability
 
파이썬 스터디 2주차
파이썬 스터디 2주차파이썬 스터디 2주차
파이썬 스터디 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
 
Hacosa js study 7th
Hacosa js study 7thHacosa js study 7th
Hacosa js study 7th
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
 
Scala
ScalaScala
Scala
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
파이썬 기본 문법
파이썬 기본 문법파이썬 기본 문법
파이썬 기본 문법
 
Data Mining with R CH1 요약
Data Mining with R CH1 요약Data Mining with R CH1 요약
Data Mining with R CH1 요약
 
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
 
파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304
 
R을 이용한 데이터 분석
R을 이용한 데이터 분석R을 이용한 데이터 분석
R을 이용한 데이터 분석
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initialization
 
06장 함수
06장 함수06장 함수
06장 함수
 

More from JiandSon

2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
JiandSon
 
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
JiandSon
 
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
JiandSon
 
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
JiandSon
 
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
JiandSon
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
JiandSon
 

More from JiandSon (6)

2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
 
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
2015.03.14 Piday in Korea 지앤선 라즈베리 미트업(박종건)
 
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - iOS 테스팅 이야기(OSXDEV)
 
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
 
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
2013.02.02 지앤선 테크니컬 세미나 - 하둡으로 배우는 대용량 데이터 분산처리 기술(이현남)
 
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
 

2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 나의 첫번째 자바8 람다식 (정대원)

  • 1. 나에 첫번째 자바8 람다식 - @blueiur(twitter)
  • 2. 오! 벌써 새벽 3시네, 컴퓨 터 끄고 자야 겠어! 한 시간 후 ... 정대원@blueiur(twitter) ● like .. ○ programming language ○ functionl programming ○ elixir ○ scala ○ ruby
  • 3. 람다 ● 람다 계산법 ● 익명 함수 ● 함수 리터럴 ● 클로저
  • 4. 익명 함수 Wikipedia ● 특정 식별자 없이 정의되거나 호출될 수 있는 함수
  • 5. 람다가 왜 필요할가? ● 행위 매개변수(코드 블럭) 전달
  • 6. // 1. 컬렉션 정렬 (익명 클래스 사용) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); 컬렉션 정렬 - 익명 클래스 사용
  • 7. // 1. 컬렉션 정렬 (익명 클래스 사용) Collections.sort(names, ...); Collections.sort + a.compareTo(b) new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }
  • 8. // 1. 컬렉션 정렬 (익명 클래스 사용) Collections.sort(names, ...); Collections.sort + [a.compareTo(b), b.compareTo(a)] new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } } new Comparator<String>() { @Override public int compare(String a, String b) { return b.compareTo(a); } }
  • 9. 새 쓰레드 생성 - 익명 클래스 사용 // 쓰레드 생성 (익명 클래스 사용) new Thread(new Runnable() { @Override public void run() { System.out.println("I consume memory, therefore i am!"); } }).start();
  • 10. // 1. 쓰레드 생성 (익명 클래스 사용) new Thread(...); new Thread(...) + System.out.println("..."); new Thread(new Runnable() { @Override public void run() { System.out.println("I consume memory, therefore i am!"); } }).start();
  • 11. // 1. 쓰레드 생성 (익명 클래스 사용) new Thread(...); new Thread(...) + [System.out.println("..."), DB.write("...")] new Thread(new Runnable() { @Override public void run() { System.out.println("I consume memory, therefore i am!"); } }).start(); new Thread(new Runnable() { @Override public void run() { DB.write("I consume memory, therefore i am!"); } }).start();
  • 12. 행위 매개변수 사용에 장점 ● 고정된 코드 + 행위 매개변수(익명 클래스) 조합을 사용한 다양한 확장 a. 더 일반화된 메서드 b. 더 유연한 인터페이스 c. 코드 중복 제거
  • 13. 요구사항 - 리스트 정렬 ● 정수형 리스트 정렬 ● 문자열 리스트 정렬 ● comparable을 상속받지 않은 객체 정렬 a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
  • 14. public static <T extends Comparable<T>> List<T> sort(List<T> list) { ArrayList<T> ls = new ArrayList<>(list); for(int i=0; i<ls.size(); i++) { int minIndex = i; for(int j=i+1; j<ls.size(); j++) { if (ls.get(j).compareTo(ls.get(minIndex)) < 0) { minIndex = j; } } T tmp = ls.get(i); ls.set(i, ls.get(minIndex)); ls.set(minIndex, tmp); } return ls; } sort(Arrays.asList("c", "b", "d", "a")) sort(Arrays.asList(1, 3, 2, 4)) Generic을 사용한 정렬 구현 comparable을 상속
  • 15. 요구사항 - 리스트 정렬 ● 정수형 리스트 정렬 ● 문자열 리스트 정렬 ● comparable을 상속받지 않은 객체 정렬 a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
  • 16. 정렬 기준을 변경하고 싶다 sort(Arrays.asList(k7, k5, k3, i30), 가격 순으로 정렬) sort(Arrays.asList(k7, k5, k3, i30), 이름 순으로 정렬) public class Car { public String name; public int price; public Car(String name, int price) { this.name = name; this.price = price; } }
  • 17. public static <T extends Comparable<T>> List<T> sort(List<T> list) { ArrayList<T> ls = new ArrayList<>(list); for(int i=0; i<ls.size(); i++) { int minIndex = i; for(int j=i+1; j<ls.size(); j++) { if (ls.get(j).compareTo(ls.get(minIndex)) < 0) { minIndex = j; } } T tmp = ls.get(i); ls.set(i, ls.get(minIndex)); ls.set(minIndex, tmp); } return ls; } 코드 분석 값 2개를 비교해서 [-1, 0, 1]중 하나를 반환
  • 18. public static <T extends Comparable<T>> List<T> sort(List<T> list) { ArrayList<T> ls = new ArrayList<>(list); for(int i=0; i<ls.size(); i++) { int minIndex = i; for(int j=i+1; j<ls.size(); j++) { if (ls.get(j).compareTo(ls.get(minIndex)) < 0) { minIndex = j; } } T tmp = ls.get(i); ls.set(i, ls.get(minIndex)); ls.set(minIndex, tmp); } return ls; } 인터페이스로 분리 interface Comparator<T> { int compare(T a, T b); } 값 2개를 비교해서 [-1, 0, 1]중 하나를 반환
  • 19. public static <T> List<T> sort(List<T> list, Comparator<T> comp) { ArrayList<T> ls = new ArrayList<>(list); for(int i=0; i<ls.size(); i++) { int minIndex = i; for(int j=i+1; j<ls.size(); j++) { if (comp.compare(ls.get(j),ls.get(minIndex) < 0) { minIndex = j; } } T tmp = ls.get(i); ls.set(i, ls.get(minIndex)); ls.set(minIndex, tmp); } return ls; } Comparator 인터페이스를 사용 interface Comparator<T> { int compare(T a, T b); } 값 2개를 비교해서 [-1, 0, 1]중 하나를 반환
  • 20. // 2. 이름으로 정렬 sort(cars, new Comparator<Car>() { @Override public int compare(Car a, Car b) { return a.name.compareTo(b.name); } }); 익명 클래스를 사용한 행동 전달 // 1. 가격으로 정렬 sort(cars, new Comparator<Car>() { @Override public int compare(Car a, Car b) { return a.price.compareTo(b.price); } }); 다른 부분 가격/이름 으로 비교
  • 21. 요구사항 - 리스트 정렬 ● 정수형 리스트 정렬 ● 문자열 리스트 정렬 ● comparable을 상속받지 않은 객체 정렬 a. 서로 다른 필드를 기준으로 정렬(ex: price, name)
  • 22. 행위 매개변수 사용에 장점 ● 고정된 코드 + 행위 매개변수(코드 블럭) 조합을 사용한 다양한 확장 a. 더 일반화된 메서드 b. 더 유연한 인터페이스 c. 코드 중복 제거
  • 23. 람다가 왜 필요할가? ● 행위 매개변수(코드 블럭) 전달 ● 자바8 이전에는 익명 클래스를 사용
  • 24. 익명 함수 Wikipedia ● 특정 식별자 없이 정의되거나 호출될 수 있는 함수 ● 자바에 함수가 있나? -> 람다!
  • 25. (인자 목록) -> { 구문 } ● x -> x + 1 ● (x) -> x + 1 ● (int x) -> x + 1 ● (int x, int y) -> x + y ● (x, y) -> { System.out.println(x + y) } ● () -> { System.out.println("runnable!"); } 람다 문법
  • 26. @Functional Interface ● 추상 메서드가 1개 뿐인 인터페이스 ● 인터페이스를 함수처럼 사용하자
  • 27. @FunctionalInterface interface Action { void run(String param); void stop(String param); } @FunctionalInterface interface Runnable() { void run(); } 메서드 1개 OK! 메서드 2개 NO!
  • 28. 익명 클래스를 람다로 변환해 주는 IntelliJ
  • 29. // 1. 람다 사용 (자바8) Collections.sort(names, (a, b) -> a.compareTo(b)); // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); 행위 매개변수 전달: 클래스 -> 람다 1:1 대응
  • 30. interface Comparator<T> { int compare(T a, T b); } 함수형 인터페이스를 사용한 정렬 // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } });
  • 31. // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); interface Comparator<T> { int compare(T a, T b); } 불필요한 객체 생성 제거, 메서드도 1개뿐이니 별도 이름 불필요 객체 이름 제거 메서드 이름 제거
  • 32. // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); interface Comparator<T> { int compare(T a, T b); } 반환 타입과 파라미터 타입도 이미 정해져 있으니 제거 객체 이름 제거 메서드 이름 제거 반환 값 및 파라미터 타입 추론
  • 33. // 1. 람다 사용 (자바8) Collections.sort(names, (a, b) -> { return a.compareTo(b); }); 비슷하다 // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } });
  • 34. 람다 문법: (인자 목록) -> { 구문 } ● x -> {return x * 2} ● x -> x * 2 ● (int x) -> x + 1 ● (int x, int y) -> x + y ● (x, y) -> { System.out.println(x + y) } ● () -> { System.out.println("runnable!"); } 실행문이 1개인 경우 {} 와 return 키워드 생략 가능
  • 35. // 1. 람다 사용 (자바8) Collections.sort(names, (a, b) -> a.compareTo(b)); 익명 클래스 -> 람다 // 1. 익명 클래스 사용 (자바8 이전) Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } });
  • 36. @FunctionalInterface interface Adder { int add(int a, int b); } ????? func = (int a, int b) -> { return a + b }; ????? shortFunc = (a, b) -> a + b; 람다 타입
  • 37. @FunctionalInterface interface Adder { int add(int a, int b); } Adder func = (int a, int b) -> { return a + b }; Adder shortFunc = (a, b) -> a + b; 람다 타입
  • 38. Q: 람다는 단순히 익명 클래스에 문법 치환인가? A: No! 실제로는 익명 클래스에 비효율을 제거하기 위해서 사용 invoke dynamic
  • 39. interface Comparator<T> { int compare(T a, T b); } 함수형 인터페이스 - 추상 메서드를 1개만 들고 있다 @FunctionalInterface interface Runnable<T> { void run(); } ???
  • 40. @FunctionalInterface 어노테이션은 붙이는 이유? ● 컴파일러가 추상 메서드가 2개인 경우 컴파일 오류 발생 ● Javadoc에 @FunctionalInterface 글 추가
  • 41. Target typing ● 람다 -> 익명 클래스 변환시 가장 유사한 타입을 찾아가는것
  • 42. public static <X, Y> void processElements( Iterable<X> source, Predicate<X> tester, Function <X, Y> mapper, Consumer<Y> block) { for (X p : source) { if (tester.test(p)) { Y data = mapper.apply(p); block.accept(data); } } } Target typing processElements( roster, p -> p.getGender() == Person.Sex.MALE // Predicate p -> p.getEmailAddress(), // Function email -> System.out.println(email) // Consumer ); 람다 두개 모두 같은 모습이지만 알아서 잘 찾아간다
  • 43. Target typing and Method arguments predicate가 왜 필요할가? Function<String, Boolean> isDaewon = s -> "daewon".equals(s); Predicate<String> isDaewon = s -> "daewon".equals(s);
  • 44. Target typing and Method arguments interface Runnable { void run(); } interface Callable<V> { V call(); } void invoke(Runnable r) { r.run(); } <T> T invoke(Callable<T> c) { return c.call(); } invoke(() -> {}); invoke(() -> "done");
  • 45. Target typing and Method arguments interface Runnable { void run(); } interface Callable<V> { V call(); } void invoke(Runnable r) { r.run(); } <T> T invoke(Callable<T> c) { return c.call(); } invoke(() -> {}); invoke(() -> "done"); 반환값을 참고해서 오버로드된 메서드도 잘 찾아간다
  • 47. public static void thread(String msg) { int tmp = 10; new Thread( () -> System.out.println(msg) ).start(); } 람다 내부에 선언되지 않은 변수를 참조할 수 있다 ● 자유변수: 나를 감싸고 있는 유효 범위 변수 a. String msg, int tmp 자신은 감싸고 있는 유효 범위 변수에 접근 가능
  • 48. public static void thread(String msg) { new Thread( () -> { msg = "must be final"; System.out.println(msg) ).start(); } } 컴파일 에러: 포획된 변수를 수정 포획된 변수는 언제나 final이여야 한다
  • 49. Function<String, Predicate<String>> startsWithFactory = s1 -> { return (s2) -> s2.indexOf(s1) > -1; }; Predicate<String> isIncludeGoogle = startsWithFactory.apply("google"); Predicate<String> isIncludeApple = startsWithFactory.apply("apple"); System.out.println(isIncludeApple.test("microsoft.com apple.com")); // true System.out.println(isIncludeGoogle.test("microsoft.com apple.com")); // false 변수 참조를 활용해서 동적으로 새로운 람다를 생성하는 람다 자신은 감싸고 있는 유효 범위 변수에 접근 가능
  • 50. 미리 정의된 함수형 인터페이스 ● 람다를 사용하려면 항상 인터페이스를 필요할가? ● 람다 사용시 새로운 인터페이스를 매번 만들어야 하나?
  • 51. 미리 정의된 함수형 인터페이스 ● 람다를 사용하려면 항상 인터페이스를 필요할가? - yes ● 람다 사용시 새로운 인터페이스를 매번 만들어야 하나? - no(반만 yes)
  • 52. Car price price > 3000 sum cars.stream().map(c -> c.gerPrice()).filter(p -> p > 3000).reduce((a, b) -> a + b)); 람다를 위해 3개 인터페이스 필요 interface Function interface Predicate interface BinaryOperator
  • 53. 미리 정의된 함수형 인터페이스 IntPredicate IntSupplier IntToDoubleFunction IntToLongFunction IntUnaryOperator LongBinaryOperator LongConsumer LongFunction<R> LongPredicate LongSupplier LongToDoubleFunction LongToIntFunction LongUnaryOperator ObjDoubleConsumer<T> ObjIntConsumer<T> ObjLongConsumer<T> Predicate<T> Supplier<T> BiConsumer<T,U> BiFunction<T,U,R> BinaryOperator<T> BiPredicate<T,U> BooleanSupplier Consumer<T> DoubleBinaryOperator DoubleConsumer DoubleFunction<R> DoublePredicate DoubleSupplier DoubleToIntFunction DoubleToLongFunction DoubleUnaryOperator Function<T,R> IntBinaryOperator IntConsumer IntFunction<R>
  • 55. // 디버그 모드에서만 실행 public void debug(String message) { if (log.isDebugEnabled()) { log.log(message); } } debug(some.expensive("operation")); 디버그 모드에서만 동작하는 함수 디버그 모드에서는 동작
  • 56. // 디버그 모드에서만 실행 public void debug(String message) { if (log.isDebugEnabled()) { log.log(message); } } debug(some.expensive("operation")); 평가 시점 함수 인자는 호출 시점에 평가가 된다
  • 57. // 디버그 모드에서만 실행 public void debug(Consumer<String> consumer) { if (log.isDebugEnabled()) { log.log(consumer.accept()); } } debug(() -> some.expensive("operation")); 람다로 평가 시점 조절 람다를 사용해서 평가를 뒤로 미룬다
  • 58. // 람다가 없는 경우 debug(some.expensive("operation")); // 람다 사용 debug(() -> some.expensive("operation")); 호출 하는 쪽이 조금 불편해 졌다
  • 59. 문제 다시 보기 ● 빌려쓰기 패턴
  • 60. public void withFile(String fileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } 파일을 한 라인씩 읽어서 STDOUT으로 출력
  • 61. public void withFile(String fileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { DB.write(line); } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } 파일을 한 라인씩 읽어서 DB에 저장
  • 62. public void withFile(String fileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { // 이 부분 외 모두 중복! } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } 중복 발생! DB.write(line); System.out.println(line); 현재 라인으로 무엇인가를 처리
  • 63. public void withFile(String fileName) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(filename)); String line = null; while ((line = bufferedReader.readLine()) != null) { // 이 부분 외 모두 중복! } } catch (IOException ex) { ex.printStackTrace(); } finally { if (bufferedReader != null) bufferedReader.close(); } } 중복 발생! interface Consumer<T> { void accept(T a); } DB.write(line); System.out.println(line);
  • 64. 어떤 값을 받아서 소비한다. interface Consumer<T> { void accept(T a); } 각 라인을 인자로 넘겨 받아서 소비한다 public void accept(String line) { System.out.println(line); }
  • 65. class DBWorker class PrintWorker class DBAndPrintWorker interface Consumer 클래스로 구현
  • 66. interface Consumer<T> { void accept(T a); } class DBWorker implements Consumer<String> { public void accept(String line) { db.store(line); } } class PrintWorker implements Consumer<String> { public void accept(String line) { System.out.println(line); } }; class DBAndPrintWorker implements Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }; withFile("input.txt", new DBWorker()); withFile("input.txt", new PrintWorker()); withFile("input.txt", new DBAndPrintWorker()); 다양한 종류에 클래스 구현
  • 67. interface Consumer<T> { void accept(T a); } withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { System.out.println(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }); 익명 클래스 사용
  • 68. interface Consumer<T> { void accept(T a); } 메서드 딱 1개! 함수형 인터페이스
  • 69. withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { System.out.println(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }); interface Consumer<T> { void accept(T a); } 익명 클래스 사용
  • 70. withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { System.out.println(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }); interface Consumer<T> { void accept(T a); } 중복되는 객체 이름 제거
  • 71. withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { System.out.println(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }); interface Consumer<T> { void accept(T a); } 중복되는 메서드 이름 제거
  • 72. withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { System.out.println(line); } }); withFile("input.txt", new Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }); interface Consumer<T> { void accept(T a); } 실제로 다른 부분은 함수 본체
  • 73. interface Consumer<T> { void accept(T a); } 람다 사용 withFile("input.txt", line -> db.store); withFile("input.txt", line -> System.out.println); withFile("input.txt", line -> { db.store(line); System.out.println(line); });
  • 74. interface Consumer<T> { void accept(T a); } class DBWorker implements Consumer<String> { public void accept(String line) { db.store(line); } } class PrintWorker implements Consumer<String> { public void accept(String line) { System.out.println(line); } }; class DBAndPrintWorker implements Consumer<String> { public void accept(String line) { db.store(line); System.out.println(line); } }; // 클래스 사용 withFile("input.txt", new DBWorker()); withFile("input.txt", new PrintWorker()); withFile("input.txt", new DBAndPrintWorker()); 불필요 코드가 많이 사라짐 // 람다 사용 withFile("input.txt", line -> db.store); withFile("input.txt", line -> System.out.println); withFile("input.txt", line -> { db.store(line); System.out.println(line); });