람다 표현식

람다를 활용해 코드를 간결하게 표현하자

Posted on 2019-07-26

람다란?

람다 표현식은 메서드로 전달할 수 있는 익명 함수를 단순화한 것이라 할 수 있다.

  • 이름이 없는 익명 함수로 파라미터 리스트, 바디, 반환 형식, 예외 리스트를 가질 수 있다.
  • 메서드 인수로 전달하거나 변수로 저장할 수 있다.
  • 익명 클래스와 달리 코드를 간결하게 구현할 수 있다.

람다 표현식

(parameters) -> expression
(int a, int b) -> a * b;

(parameters) -> { statements; }
(Apple a) -> { 
  System.out.println(a.getColor());
}

함수형 인터페이스란?

함수형 인터페이스는 추상 메서드가 오직 하나인 인터페이스를 의미한다.
함수 디스크립터는 람다 표현식의 시그니처를 서술하는 메서드다.

// 함수형 인터페이스
@FunctionalInterface
public interface Predicate<T> {
  // 함수 디스크립터 : T -> boolean
  boolean test(T t);
}
  • @FunctionalInterface 는 함수형 인터페이스임을 가리키는 어노테이션이다.
  • 함수형 인터페이스라는 문맥에서 람다 표현식을 사용할 수 있다.
  • 람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 전체 표현식을 함수형 인터페이스의 인스턴스(함수형 인터페이스를 concrete 구현한 클래스의 인스턴스)로 취급할 수 있다.
  • 제네릭 파라미터에는 참조형만 사용할 수 있다. 기본형에 대해서는 오토박싱을 피할 수 있도록 특화된 함수형 인터페이스를 제공한다.
    • IntPredicate, LongConsumer, DoubleFunction, ToLongFunction

자바8의 대표적인 함수형 인터페이스

함수형 인터페이스 함수 디스크립터 추상 메서드
Predicate<T> T -> boolean test
Consumer<T> T -> void accept
Function<T, R> T -> R apply
Supplier<T> () -> T get
UnaryOperator<T> T -> T apply
BinaryOperator<T> (T, T) -> T apply
BiPredicate<L, R> (L, R) -> boolean test
BiConsumer<T, U> (T, U) -> void accept
BiFunction<T, U, R> (T, U) -> R void apply

메서드 레퍼런스란?

  • 하나의 메서드를 참조하는 람다를 간결하게 표현 할 수 있다.
  • 명시적으로 메서드명을 참조하므로 가독성이 향상된다.
  • 기존의 메서드 구현을 재사용하고 직접 전달할 수 있다.
Lambda Expression - (Apple a) -> a.getWeight()
Method Reference - Apple::getWeight

생성자 레퍼런스는 ClassName::new 형식으로 만든다.

Supplier<Apple> c1 = Apple::new;
Apple a1 = c1.get();

Function<Integer, Apple> c2 = Apple::new;
Apple a2 = c2.apply(100);

BiFunction<String, Integer, Apple> c3 = Apple::new;
Apple a3 = c3.apply("green", 100);

함수형 인터페이스는 람다 표현식을 조합할 수 있는 다양한 디폴트 메서드를 제공한다.

  • Comparator : thenComparing
  • Predicate : negate, and, or
  • Function : andThen, compose

학습 내용을 토대로 코드를 간결하게 표현해보자

// 1. 동작을 파라미터화하여 코드 전달
public class AppleComparator implements Comparator<Apple> {
  public int compare(Apple a1, Apple a2) {
    return a1.getWeight().compareTo(a2.getWeight());
  }
}

inventory.sort(new AppleComparator());
// 2. 익명클래스 사용
inventory.sort(new Comparator<Apple>() {
  public int compare(Apple a1, Apple a2) {
    return a1.getWeight().compareTo(a2.getWeight());
  }
});
// 3. 람다 표현식 사용
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
inventory.sort(comparing((a -> a.getWeight()));
// 4. 메서드 레퍼런스 사용
inventory.sort(comparing(Apple::getWeight()));


Reference
  • Java8 in Action