람다 표현식
람다 표현식 이란?
익명함수를 단순화 한 것. 람다 표현식을 사용하면 동작 파라미터를 이용하는 코드를 더 쉽고 간결하게 작성할 수 있다.
람다 표현식의 구조
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight));
Java
복사
•
매개변수 리스트
•
화살표
•
람다 바디
◦
표현식
◦
여러 행의 문장을 포함하는 블록.
함수형 인터페이스
람다 표현식은 함수형 인터페이스를 표현하는 문맥에서만 사용할 수 있다.
함수형 인터페이스란 추상 메서드를 한개만 가지는 인터페이스이다. 디폴트 메서드나 정적 메서드와는 무관하다.
람다 표현식은 결과적으로 함수형 인터페이스를 구현한 클래스의 인스턴스로서 동작한다.
람다식 활용 : 실행 어라운드 패턴
초기화&준비 코드와 정리&마무리 코드가 실제 작업 코드 앞뒤에 등장하는 형태의 패턴을 실행 어라운드 패턴이라 한다.
실행 어라운드 패턴은 동작 파라미터를 적용하기 아주 좋은 패턴이다.
실행 어라운드 패턴에 동작 파라미터와 람다식을 적용하는 과정
1 → 3 이 동작 파라미터화 과정이고, 3 → 4 가 람다식을 적용한 과정이다.
표준 함수형 인터페이스
Java 8 에는 범용적인 상황에서 사용할 수 있는 함수형 인터페이스가 추가되었다. java.util.function 에 속해있다.
Predicate<T>
T 타입을 입력받아 boolean 을 반환하는 test(T t); 메서드를 제공한다. 어떤 입력이 특정 조건을 만족하는지 확인하는 용도로 사용할 수 있다.
negate, and, or 이라는 default 메서드를 제공해 여러 Predicate 를 조합하여 사용할 수 있도록 되어있다.
Predicate<Apple> redBigApple = Apple::isRed;
redBigApple = redBigApple.and(Apple::isBig);
Java
복사
Consumer<T>
T 타입을 입력받아 사용하고 아무것도 반환하지 않는 accept(T t); 메서드를 제공한다. 입력을 그대로 사용하는 용도로 사용할 수 있다.
Function<T, R>
T 타입을 입력받아 R 타입을 반환하는 apply(T t); 메서드를 제공한다. 어떤 입력을 다른 것으로 변환하는 용도로 사용할 수 있다.
andThen 과 compose 메서드를 통해 연결할 수 있다.
Function<Integer,Integer> f = x -> x+1;
Function<Integer,Integer> g = x -> x*2;
Function<Integer,Integer> h = f.andThen(g);
h.apply(1); // 4
Java
복사
Function<Integer,Integer> f = x -> x+1;
Function<Integer,Integer> g = x -> x*2;
Function<Integer,Integer> h = f.compose(g);
h.apply(1); // 3
Java
복사
Supplier<T>
아무 입력을 받지 않고 T 타입을 반환하는 get(); 메서드를 제공한다. 객체를 생성하는데 사용할 수 있다.
이 외에도 여러 함수형 인터페이스들이 있다.
형식 검사
람다 표현식에는 람다식이 어떤 인터페이스의 구현체로 동작하는지 명시되지 않는다. 따라서 컴파일러는 이를 추론해야 한다.
람다 표현식 타입 추론 과정
람다식이 대입되는 파라미터나 변수의 타입을 보고 추론한다.
따라서 같은 람다식이 다른 함수형 인터페이스의 구현체로 동작할 수 있다!
Callable<Integer> c = () -> 42; // Callable
Supplier<Integer> s = () -> 42; // Supplier
Java
복사
메서드 참조
이미 정의된 메서드 구현을 재사용하는 경우 람다식을 더 단순화하여 사용할 수 있는 문법이다.
클래스::인스턴스메서드 는 람다식의 매개변수가 클래스 타입이고, 그것의 인스턴스 메서드를 호출한다는 의미고,
인스턴스 참조::인스턴스 메서드는 람다식에서 외부 인스턴스의 메서드를 호출한다는 의미이다.
String str = "hello";
Consumer<String> c = String::isEmpty; // (String str) -> str.isEmpty();
Predicate<String> p = str::equals; // (String s) -> str.equals(s);
Java
복사
메서드 참조는 익숙하지 않으면 해석하기 힘들정도로 표현이 생략되기 때문에 사용에 주의가 필요하다.