View
1.255
Download
2
Category
Preview:
DESCRIPTION
지난 26일(2014/7/26), 지앤선과 KSUG가 함께 진행했던 세미나에서 발표한 람다 관련 내용입니다. 첫 시간에 정대원님이 발표하신 람다 기본에 다루지 않은 내용만 정리했는데 지난 번에 올렸던 자료(http://www.slideshare.net/gyumee/java-8-lambda-35352385)의 후편으로도 볼 수 있을 것 같습니다. 제 발표는 장표만으로 내용을 가늠하기 어려운데 그래도 이번에는 청각 장애인들도 참여한다고 해서 장표에 글자를 많이 넣으려고 했습니다.
Citation preview
나머지
박성철
자바8람다 이야기
SK Planet, 한국 스프링 사용자 모임(KSUG)
박성철(fupfin)
노땅 개발자(라고 착각하는 관리자)
엄청 망해봤어요
산만해요
람다에서 필요한 건 이미 다 배웠습니다
와~
뭐?!
메서드 참조method reference
람다는 뭘까?
Runnable����������� ������������������ task����������� ������������������ =����������� ������������������ ()����������� ������������������ ->����������� ������������������ {����������� ������������������ System.out.println(“Hello����������� ������������������ world”);};����������� ������������������ new����������� ������������������ Thread(task).start();
메서드?객체
람다는 무명 클래스를 쉽게 만들 수 있는 언어 장치?
void����������� ������������������ noname(){����������� ������������������ System.out.println(“Hello����������� ������������������ world”);};람다 ≃ 무명 메서드
public����������� ������������������ class����������� ������������������ MethodRefExample����������� ������������������ {����������� ������������������ !����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String����������� ������������������ args[])����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ List<String>����������� ������������������ list����������� ������������������ =����������� ������������������ Arrays.asList("A",����������� ������������������ "B",����������� ������������������ "C",����������� ������������������ "D");����������� ������������������ ����������� ������������������ ����������� ������������������ list.forEach((e)����������� ������������������ ->����������� ������������������ printWithTime(e));����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ printWithTime(String����������� ������������������ str)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ out.println("["����������� ������������������ +����������� ������������������ currentTimeMillis()����������� ������������������ +����������� ������������������ "]����������� ������������������ "����������� ������������������ +����������� ������������������ str);����������� ������������������ ����������� ������������������ }����������� ������������������ }����������� ������������������
void����������� ������������������ forEach(Consumer<?����������� ������������������ super����������� ������������������ T>����������� ������������������ action)
Consumer<T>����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ void����������� ������������������ accept(T����������� ������������������ t);����������� ������������������ }
동일 시그니처
메서드 참조
public����������� ������������������ class����������� ������������������ MethodRefExample����������� ������������������ {����������� ������������������ !����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String����������� ������������������ args[])����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ List<String>����������� ������������������ list����������� ������������������ =����������� ������������������ Arrays.asList("A",����������� ������������������ "B",����������� ������������������ "C",����������� ������������������ "D");����������� ������������������ ����������� ������������������ ����������� ������������������ list.forEach(MethodRef::printWithTime);����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ printWithTime(String����������� ������������������ str)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ out.println("["����������� ������������������ +����������� ������������������ currentTimeMillis()����������� ������������������ +����������� ������������������ "]����������� ������������������ "����������� ������������������ +����������� ������������������ str);����������� ������������������ ����������� ������������������ }����������� ������������������ }����������� ������������������
기존에 만들어진 메서드를 명칭을 사용해서 참조하는 표현
메서드 참조의 종류
1) 정적 메서드 참조2) 객체 메서드 참조3) 람다 인자 객체 메서드 참조4) 생성자 참조5) 상위 클래스의 메서드 참조6) 배열 생성자
정적 메서드 참조
public����������� ������������������ class����������� ������������������ MethodRef����������� ������������������ {����������� ������������������ !����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String����������� ������������������ args[])����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ List<String>����������� ������������������ list����������� ������������������ =����������� ������������������ Arrays.asList("123",����������� ������������������ "241",����������� ������������������ "212");����������� ������������������ ����������� ������������������ ����������� ������������������ int����������� ������������������ sum����������� ������������������ =����������� ������������������ list.stream().mapToInt(Integer::parseInt).sum();����������� ������������������ ����������� ������������������ }����������� ������������������ }
특정 클래스의 정적 메서드 참조
클래스 이름::메서드 이름
객체 메서드 참조
public����������� ������������������ class����������� ������������������ MethodRefExample����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String����������� ������������������ args[])����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ List<String>����������� ������������������ list����������� ������������������ =����������� ������������������ Arrays.asList("A",����������� ������������������ "B",����������� ������������������ "C");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ list.forEach(System.out::println);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
특정 객체의 멤버 메서드 참조
객체 참조::메서드 이름
람다 인자 객체 메서드 참조
public����������� ������������������ class����������� ������������������ MethodRefExample����������� ������������������ {����������� ������������������ !����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String����������� ������������������ args[])����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ Integer[]����������� ������������������ values����������� ������������������ =����������� ������������������ null;����������� ������������������ ����������� ������������������ ����������� ������������������ Arrays.sort(values,����������� ������������������ Integer::compare);����������� ������������������ ����������� ������������������ }����������� ������������������ }
람다의 인자로 넘어오는 객체의 멤버 메서드 참조
e����������� ������������������ ->����������� ������������������ e.someMethod();����������� ������������������ (e1,����������� ������������������ e2)����������� ������������������ ->����������� ������������������ e1.someMethod(e2);
SomeObject::someMethod����������� ������������������ SomeObject::someMethod
인자의 타입명::메서드 이름
생성자 참조
List<Integer>����������� ������������������ list����������� ������������������ =����������� ������������������ null;����������� ������������������ list.stream().mapToObject(Integer::new).…⋯…⋯����������� ������������������
()����������� ������������������ ->����������� ������������������ e����������� ������������������ ->����������� ������������������ (e1,����������� ������������������ e2)����������� ������������������ ->����������� ������������������ new����������� ������������������ SomeObject(e1,����������� ������������������ e2);
SomeObject::new����������� ������������������ SomeObject::new����������� ������������������ SomeObject::new
해당하는 인자를 받는 객체 생성자의 참조
클래스 이름::
상위 클래스 메서드 참조
상속 관계의 상위 클래스 메서드 참조
super::메서드 이름
배열 생성자 참조
특정 타입의 배열 생성자 참조
타입명[]::new
정리
람다 표현 대신 메서드의 참조를 사용 가능클래스(또는 객체)::메서드 이름정적 메서드 참조, 객체 메서드 참조, 생성자 참조함수 인터페이스가 아니라도 기존 메서드를 람다 표현 대신 사용
this의 범위
public����������� ������������������ class����������� ������������������ LambdaExample����������� ������������������ {����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ sort(List<Integer>����������� ������������������ list)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ list.sort(new����������� ������������������ Comparator<Integer>()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ public����������� ������������������ int����������� ������������������ compare(Integer����������� ������������������ i1,����������� ������������������ Integer����������� ������������������ i2)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ this.count();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ i1.compareTo(i2);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ });����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ private����������� ������������������ void����������� ������������������ count()����������� ������������������ {…⋯}����������� ������������������ }
LambdaExample.this.count();
무명 클래스 vs 람다
public����������� ������������������ class����������� ������������������ LambdaExample����������� ������������������ {����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ sort(List<Integer>����������� ������������������ list)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ list.sort((i1,����������� ������������������ i2)����������� ������������������ ->����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ this.count();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ i1.compareTo(i2);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ });����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ private����������� ������������������ void����������� ������������������ count()����������� ������������������ {…⋯}����������� ������������������ }
응? 람다도 객체
아닌가? 왜 자신을
안 가리키지?
public����������� ������������������ class����������� ������������������ LambdaExample����������� ������������������ {����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ sort(List<Integer>����������� ������������������ list)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ list.sort(this::lambda$0);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ private����������� ������������������ void����������� ������������������ count()����������� ������������������ {…⋯}����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ private����������� ������������������ int����������� ������������������ lambda$0(Integer����������� ������������������ i1,����������� ������������������ Integer����������� ������������������ i2)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ this.count();����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ i1.compareTo(i2);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
public����������� ������������������ class����������� ������������������ LambdaExample����������� ������������������ {����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ sort(List<Integer>����������� ������������������ list)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ list.sort((i1,����������� ������������������ i2)����������� ������������������ ->����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ this.count();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ i1.compareTo(i2);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ });����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ private����������� ������������������ void����������� ������������������ count()����������� ������������������ {…⋯}����������� ������������������ }
초간단 요약 람다의 처리
정리
람다는 새로운 객체를 만들지 않음this는 내가 알던 그 this비밀이 숨어 있지만… MethodHandle…
기본 메서드default method
API의 고민, 하위 호환성
“객체지향 모델은 신중히 설계해서 클래스 라이브러리가 변한다고 이미 컴파일된 애플리케이션이 망가지지 않도록 해야 한다. 정말로, 애플리케이션은 망가뜨리지 말아라.”
---Ira Forman, Michael Conner, Scott Danforth, and Larry Raper, "Release-to-Release Binary Compatibility in SOM", in Proceedings of OOPSLA '95.
"An object-oriented model must be carefully designed so that class-library transformations
that should not break already compiled applications, indeed, do not break such applications.”
API의 고민, 하위 호환성
“Adding new fields, methods, or constructors to an existing class or interface. “
기존 클래스나 인터페이스에 새 필드, 메서드, 생성자 추가시 하위 호환성이 깨진다.
깨어진 하위 호환성
자바 인터페이스의 호환성 문제
자바 인터페이스의 모든 메서드는 공개(public) 추상(abstract) 메서드이므로 새로운 메서드를 추가하면 이 인터페이스를 구현한 모든 클래스는 추가된 메서드를 구현해서 새로 컴
파일 해야 한다.
자바 인터페이스 개선 전략
1) 호환성 무시! 내가 고치겠다는데 뭐… (쓰는 사람도 없고)
2) 새 술은 새 부대에, 새 메서드는 새 인터페이스에… 기존 인터페이스를 확장한 새 인터페이스 생성, 버전 인터페이스
3) 기본 추상 클래스 제공고객이 인터페이스를 구현하는 대신 기본 제공되는 추상 객체를 확장하도록 권장
4) 그리고 전통적인 자바 API의 방법…
고치지 않는다…
하위 호환성을 버려야 할 위기
람다의 도입은 단순한 표현 방법 추가 이상의 의미“OOP 방식 외 새로운 추상화 기법 도입”자바 SDK의 기본 API의 대대적인 변형 필수
하지만 자바가 하위 호환성을 버릴 수는…
기본 메서드 구현
새로 추가하는 메서드에 기본 구현을 넣자!!
interface����������� ������������������ MyInterface����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ int����������� ������������������ existingMethod();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ 기본으로����������� ������������������ 수행할����������� ������������������ 로직����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ }����������� ������������������ }
기본 메서드
기본 메서드 사용
기본 메서드는 클래스에서 구현하지 않아도 사용 가능
interface����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {����������� ������������������ }����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ class����������� ������������������ FooImpl����������� ������������������ implements����������� ������������������ Foo����������� ������������������ {����������� ������������������ }����������� ������������������ !!new����������� ������������������ FooImpl().newMethod();
상속
기본 메서드 상속
인터페이스 상속시 기본 메서드 구현도 상속하위 인터페이스가 재정의(override) 가능
interface����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ interface����������� ������������������ Bar����������� ������������������ extends����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }����������� ������������������ !class����������� ������������������ BarImpl����������� ������������������ implements����������� ������������������ Bar����������� ������������������ {����������� ������������������ }����������� ������������������ !!new����������� ������������������ BarImpl().newMethod();
다중 상속
객체메세지
행위
상태 추상/구상클래스
자바7이전인터페이스
자바8인터페이스
단일 상속만 허용 다중 상속 허용 다중 상속 허용
메시지의 다중 상속 메시지와 구현의다중 상속
충돌 발생
다중 상속 구현 충돌
자바 7 이전: 구현의 다중 상속 불가자바 8부터: 기본 메서드로 인해 구현 충돌 문제 발생
interface����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ interface����������� ������������������ Bar1����������� ������������������ extends����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }����������� ������������������ !interface����������� ������������������ Bar2����������� ������������������ extends����������� ������������������ Foo����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ class����������� ������������������ BarImpl����������� ������������������ implements����������� ������������������ Bar1,����������� ������������������ Bar2����������� ������������������ {����������� ������������������ }
Foo
Bar1 Bar2
BarImpl
다이아몬드 문제
컴파일 에러!!!
다이아몬드 문제 회피법충돌 기본 메서드 재정의(Override)class����������� ������������������ BarImpl����������� ������������������ implements����������� ������������������ Bar1,����������� ������������������ Bar2����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {…⋯}����������� ������������������ }
Foo
Bar1 Bar2
BarImpl상속 방향 선택class����������� ������������������ BarImpl����������� ������������������ implements����������� ������������������ Bar1,����������� ������������������ Bar2����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Bar1.super.newMethod();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ …⋯����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
Foo
Bar1 Bar2
BarImpl
상속 순서 선택class����������� ������������������ BarImpl����������� ������������������ implements����������� ������������������ Bar1,����������� ������������������ Bar2����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ default����������� ������������������ void����������� ������������������ newMethod()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Bar1.super.newMethod();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Bar2.super.newMethod();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
Foo
Bar1 Bar2
BarImpl1 2
기본 메서드와 트레잇(Trait)
OOP에서 다른 클래스의 기능을 확장하는데 사용되는 메서드의 집합보통 인터페이스와 믹스인 중간에 해당한다. 인터페이스는 메서드 선언만 있고, 트레잇은 정의까지 포함한다. 믹스인은 상태를 가지지만 트레잇은 보통 상태를 가지지 않는다.
기본 메서드와 트레잇(Trait)
OOP에서 다른 클래스의 기능을 확장하는데 사용되는 메서드의 집합보통 인터페이스와 믹스인 중간에 해당한다. 인터페이스는 메서드 선언만 있고, 트레잇은 정의까지 포함한다. 믹스인은 상태를 가지지만 트레잇은 보통 상태를 가지지 않는다.
인터페이스 정적 메서드
기본 구현과 함께 인터페이스에도 정적 메서드 정의 가능편의 메서드(utility method)를 위한 이름 공간(Name space)로서의 인터페이스
interface����������� ������������������ StringUtils����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ String����������� ������������������ reverse(String����������� ������������������ str){…⋯}����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ String����������� ������������������ capitalize(String����������� ������������������ str)����������� ������������������ {…⋯}����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ String����������� ������������������ delete(String����������� ������������������ inString,����������� ������������������ String����������� ������������������ pattern)����������� ������������������ {…⋯}����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ …⋯…⋯����������� ������������������ }
정리
인터페이스에 메서드 구현 가능기본 메서드는 상속, 재정의 가능바이너리 하위 호환성을 유지하고 기존 인터페이스에 메서드 추가다중 상속시 재정의, 상속 방향 선택 등으로 충돌 회피정적 메서드 정의 가능
기본 제공 함수 인터페이스java.util.function.*
범용 함수형 인터페이스
java.util.function 패키지에 범용으로 사용될 다양한 함수형 인터페이스 기본 제공
Consumer<T>BiConsumer<T,U>Function<T,R>BiFunction<T,U,R>Predicate<T>Supplier<T>UnaryOperator<T>BinaryOperator<T>
void accept(T t)void accept(T t, U u)R apply(T t)R apply(T t, U u)boolean test(T t)T get()T apply(T t)T apply(T t1, T t2)
기본 타입용 변종
Consumer<T>
Function<T,R>
Predicate<T>
Supplier<T>
UnaryOperator<T>
Int
Double
Long
기본 타입 변환 함수 인터페이스
Double
Function<T,R>: T 타입을 R타입으로 바꾸는 함수 인터페이스
Int
Long
Double
Int
Long
IntToDoubleFunctionLongToDoubleFunction
DoubleToIntFunctionLongToIntFunction
DoubleToLongFunctionIntToLongFunction
정리
다양한 범용 함수 인터페이스를 기본으로 제공삽질하지 말자
END_OF_THIRD_WAVE
Recommended