지난 26일(2014/7/26), 지앤선과 KSUG가 함께 진행했던 세미나에서 발표한 람다 관련 내용입니다.
첫 시간에 정대원님이 발표하신 람다 기본에 다루지 않은 내용만 정리했는데 지난 번에 올렸던 자료(http://www.slideshare.net/gyumee/java-8-lambda-35352385)의 후편으로도 볼 수 있을 것 같습니다.
제 발표는 장표만으로 내용을 가늠하기 어려운데 그래도 이번에는 청각 장애인들도 참여한다고 해서 장표에 글자를 많이 넣으려고 했습니다.
동작 파라미터와 람다(Java 8 in Action)
자바8 in Action을 읽고 정리해본 내용입니다.
자바8은 함수형 패러다임과 멀티 코어에서의 병렬 처리를 돕는 방향으로 출시되었습니다.
‘자바 8 in Action’ 책을 읽고 ppt로 정리해봤습니다.
어떻게 해서 람다와 메서드 레퍼런스 개념까지 자바8에 도입이 되었는지 설명하는 문서입니다.
주요 키워드
동작 파라미터화(Behavior Parameterization), 값 파라미터화, 익명 클래스, 람다
지난 26일(2014/7/26), 지앤선과 KSUG가 함께 진행했던 세미나에서 발표한 람다 관련 내용입니다.
첫 시간에 정대원님이 발표하신 람다 기본에 다루지 않은 내용만 정리했는데 지난 번에 올렸던 자료(http://www.slideshare.net/gyumee/java-8-lambda-35352385)의 후편으로도 볼 수 있을 것 같습니다.
제 발표는 장표만으로 내용을 가늠하기 어려운데 그래도 이번에는 청각 장애인들도 참여한다고 해서 장표에 글자를 많이 넣으려고 했습니다.
동작 파라미터와 람다(Java 8 in Action)
자바8 in Action을 읽고 정리해본 내용입니다.
자바8은 함수형 패러다임과 멀티 코어에서의 병렬 처리를 돕는 방향으로 출시되었습니다.
‘자바 8 in Action’ 책을 읽고 ppt로 정리해봤습니다.
어떻게 해서 람다와 메서드 레퍼런스 개념까지 자바8에 도입이 되었는지 설명하는 문서입니다.
주요 키워드
동작 파라미터화(Behavior Parameterization), 값 파라미터화, 익명 클래스, 람다
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)MIN SEOK KOO
이것이 자바다 Chap.14 람다식 Lambda expression(java) 발표용 PPT
간단하게 정리한 것.
이것이 자바다 책을 기반으로 작성한 강의용 PPT입니다.
부족한 게 많으니 쓰실 때에는 추가하셔서 쓰세요~
참고 자료 : 이것이 자바다
사진 첨부 : http://palpit.tistory.com/
이것이 자바다 익명 객체 + Chap.11 기본 API 클래스(java) 발표용 PPT.
간단하게 정리한 것.
이것이 자바다 책을 기반으로 작성한 강의용 PPT입니다.
부족한 게 많으니 쓰실 때에는 추가하셔서 쓰세요~
참고 자료 : 이것이 자바다
사진 첨부 : http://palpit.tistory.com/
스트림 API는 람다 표현식을 적극적으로 활용해서 만들어진 자바의 새로운 API 입니다.
스트림 API를 통해서 자바에서도 맵/리듀스 방식으로 대량의 데이터를 순차 또는 병렬 처리를 할 수 있게 되었는데요, 이번 발표를 통해 스트림 API가 무엇인지- 어떻게 써먹는지에 대해 가볍게 씹고 뜯고 맛보고 즐기셨으면 좋겠습니다. :)
예제코드 : https://github.com/arawn/jdk8-stream-api
이것이 자바다 Chap.14 람다식 Lambda expression(java)(KOR)MIN SEOK KOO
이것이 자바다 Chap.14 람다식 Lambda expression(java) 발표용 PPT
간단하게 정리한 것.
이것이 자바다 책을 기반으로 작성한 강의용 PPT입니다.
부족한 게 많으니 쓰실 때에는 추가하셔서 쓰세요~
참고 자료 : 이것이 자바다
사진 첨부 : http://palpit.tistory.com/
이것이 자바다 익명 객체 + Chap.11 기본 API 클래스(java) 발표용 PPT.
간단하게 정리한 것.
이것이 자바다 책을 기반으로 작성한 강의용 PPT입니다.
부족한 게 많으니 쓰실 때에는 추가하셔서 쓰세요~
참고 자료 : 이것이 자바다
사진 첨부 : http://palpit.tistory.com/
스트림 API는 람다 표현식을 적극적으로 활용해서 만들어진 자바의 새로운 API 입니다.
스트림 API를 통해서 자바에서도 맵/리듀스 방식으로 대량의 데이터를 순차 또는 병렬 처리를 할 수 있게 되었는데요, 이번 발표를 통해 스트림 API가 무엇인지- 어떻게 써먹는지에 대해 가볍게 씹고 뜯고 맛보고 즐기셨으면 좋겠습니다. :)
예제코드 : https://github.com/arawn/jdk8-stream-api
[소스 코드]
https://github.com/henlix/data-structure.git
[설명]
대학생 연합 IT 벤처 창업 동아리 S.O.P.T (Shout Our Passion Together - http://sopt.org) 에서 내부적으로 진행하는 전공 과목 기초 스터디 자료입니다.
이번주에 다룰 내용은 전반적인 개요, 복잡도 분석 및 기초 데이터 구조인 배열과 연결리스트 기초입니다.
스터디 자료는 다음과 같은 순서대로 올라갈 예정입니다.
1. 데이터 구조 및 알고리즘
2. 운영체제
3. 네트워크
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 이전에는 익명 클래스를 사용
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);
}
});
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
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"));
호출 하는 쪽이 조금 불편해 졌다
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);
});