4. 람다식(lambda expression)
● 단순히 정의하면, 프로그래밍에서 식별값 없이 실행
할 수 있는 함수 표현 방법
o 이미 많은 언어에서 지원: Ruby, C#, Python,
o 람다식을 이용한 함수를 생성 예
§ scala: someList.filter(x => x > 0)
● 함수형(Functional) 언어에서 함수는 1급(first-
level class)임
o 함수를 변수에 할당, 파라미터로 전달하는 게 가능
● 자바는 함수가 없는데...?
5. 자바8의 람다식
● 함수형(Functional) 인터페이스의 임의 객체를 람
다식으로 표현
o 함수형 인터페이스: 추상 메서드가 1개인 인터페이스
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparator<Long> comp = (Long o1, Long o2) -> o2 - o1 < 0 ? -1 : 1
7. 몇 가지 람다식 예
public interface Operator<T> {
public T operate(T op1, T op2);
}
public interface Callable<V> {
V call() throws Exception;
}
public interface Runnable {
public void run();
}
public interface Predicate<T> {
boolean test(T t);
}
// 파라미터 타입 지정
Comparator<Long> longComparator =
(Long first, Long second) -> Long.compare(first, second);
// 파라미터 타입 지정하지 않음, 문맥에서 유추
Comparator<Long> longComparator =
(first, second) -> Long.compare(first, second);
// 파라미터가 한 개인 경우, 파라미터 목록에 괄호 생략
Predicate<String> predicate = t -> t.length() > 10;
// 파라미터가 없는 경우
Callable<String> callable = () -> "noparam";
// 결과 값이 없는 경우
Runnable runnable = () -> System.out.println("no return");
// 코드 블록을 사용할 경우, return을 이용해서 결과 값을 리턴
Operator<Integer> plusSquareOp = (op1, op2) -> {
int result = op1 + op2;
return result * result;
};
8. 람다식과 프리 변수
int multiple = 10;
Operator<Integer> operator = (x) -> x * multiple;
int result = operation( operator );
프리 변수(free variable):
람다식의 파라미터나 식 내부에서 선언되지 않은 변수
● 자바는 람다식에서 사용하는 프리변수의 값을 변경할 수 없음
● 임의 객체의 경우 프리 변수를 반드시 final로 지정해야 했지만, 람다식의
경우 프리 변수의 값이 바뀌지 않으면 컴파일러가 에러를 발생하지 않음
9. 몇 가지 미리 정의된 함수형 인터페이스
java.util.function 패키지에 다양한 상황
에 사용할 수 있는 함수형 인터페이스 정
의됨
public interface Function<T, R> {
R apply(T t);
}
public interface Predicate<T> {
boolean test(T t);
}
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
public interface Supplier<T> {
T get();
}
public interface Consumer<T> {
void accept(T t);
}
10. 함수형 인터페이스 강제
● @FuntionalInterface 사용
o @FuntionalInterface가 붙은 인터페이스가 추상 메서드를
두 개 이상 가지면 컴파일 에러 발생!
@FunctionalInterface
public interface Operator<T> {
public T operate(T op1, T op2);
}
11. 메서드 레퍼런스
기존 코드
public class SomeView
implements OnClickListener {
private void init() {
myBtn.setOnClickListener(this);
youBtn.setOnClickListener(this);
}
@Override
public void onClick(ClickEvent e) {
…
if (e.getSource() == myBtn) {
...
}
}
}
메서드 레퍼런스 사용
public class SomeView {
private void init() {
myBtn.setOnClickListener(this::onMyBtnClick);
youBtn.setOnClickListener(this::onYouBtnClick);
}
private void onMyBtnClick(ClickEvent e) {
...
}
private void onYouBtnClick(ClickEvent e) {
...
}
}
12. 메서드 레퍼런스 종류
● 클래스::정적메서드
o someOperation( Op::square );
§ someOperation( (x, y) -> Op.square(x, y) );
● 객체::인스턴스메서드
o someOperation( obj::square );
§ someOperation( (x, y) -> obj.square(x, y) );
o someOperation( this::square );
o someOperation( super::square );
● 클래스::인스턴스메서드
o someOperation( XClass::double )
§ someOperation( (x, y) -> x.double(y) )
13. 인터페이스의 변화
● 디폴트 메서드(default method)
o 인터페이스 메서드가 구현을 가질 수 있음
● 정적 메서드
o 인터페이스가 정적 메서드를 가질 수 있음
14. 디폴트 메서드
public interface Collection<E> extends Iterable<E> {
Iterator<E> iterator();
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
LinkedList<Long> list = ….;
list.removeIf((e) -> e > 10L);
15. 디폴트 메서드의 우선 순위
class Team {
public int version() {
return 0;
}
}
interface Verion {
default int version() {
return -1;
}
}
interface Lockable {
default int version() {
return 1;
}
}
class ExtTeam
extends Team
implements Version {
}
항상 클래스가 우선순위 가짐
- ExtTeam 객체의 getVersion()은
Team 클래스의 getVersion() 사용
class Job implements
Version, Lockable {
@Override
public int version() {
return Version.super.getName()
}
}
상속받은 인터페이스들의 같은 시그너처
를 갖는 메서드 중 한 개라도 디폴트 메서
드가 있으면,
하위 타입에서 재정의해 주어야 함
16. Optional과 람다식의 만남
● java.util.Optional이란?
o 값이 있거나 또는 없는 경우를 표현하기 위한 클래스
o 간단한 예
§ Optional<Long> value = someMethod();
if (value.isPresent()) {
Long val = value.get();
}
o map, filter 등의 고차원(higher order) 함수를 가짐
§ public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
§ public Optional<T> filter(Predicate<? super T> predicate)
§ public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
17. Optional과 람다식의 만남
● Optional과 고차원 함수의 조합
Optional<Member> mem = findMemberById(1L);
Coord result = mem.map(Member::getAddress)
.map(address -> address.getZipCode())
.map(zipCode -> findCoord(zipCode))
.orElse(null);
Member mem = findMemberById(1L);
Coord result = null;
if (mem != null) {
if (mem.getAddress() != null) {
String zipCode = mem.getAddress().getZipCode();
if (zipCode != null) result = findCoord(zipCode);
}
}
18. 기타
● 자바8 스트림API: 함수형 인터페이스 천국
o filter(Predicate)
o map(Function)
o sorted(Comparator)
o forEach(Consumer)
o reduce(identity, BinaryOperator)
o …