ITEM 43: 람다보다는 메서드 참조를 사용해라

람다의 가장 큰 장점은 간결함이다. 함수객체를 람다 보다 더 간결하게 구현할 수 있는 메서드 참조(method reference)에 대해 이번장에서 다뤄볼 것이다.

    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if (newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }

Java 8때 Map에 추가된 merge 메서드는 키, 값, 함수를 인수로 받는다. 주어진 키가 맵에 없다면 주어진 키, 값을 그대로 저장하고, 반대로 키가 이미 있다면 {키, 함수의 결과} 쌍을 저장한다.

// 키가 맵 안에 없으면 키와 숫자 1을 매핑하고, 이미 있다면 기존 매핑 값을 증가
map.merge(key, 1, (count, incr) -> count + incr);

merge 메서드의 전형적인 쓰임을 잘 보여준다. 위 람다는 두 인수의 합을 단순히 반환할 뿐이지만, 매개변수인 countincr은 크게 하는 일 없이 공간을 차지하는 것을 볼 수 있다.

Java8부터 Integer 클래스(모든 기본타입의 박싱 타입)는 위 람다와 기능이 같은 정적 메서드 sum 을 제공하기 시작했다.

public final class Integer extends Number implements Comparable<Integer> {
  ...
  public static int sum(int a, int b) {
        return a + b;
  }
  ...
}

람다대신 메서드 참조를 전달하면 똑같은 결과도 더 간결하게 구현할 수 있다.

map.merge(key, 1, Integer::sum);

하지만 매개변수의 이름 자체가 프로그래머에게 좋은 가이드가 되는 경우에는 람다를 사용하는 것이 유지보수에 더 좋을 수 있다. 그렇더라도 메서드 참조를 사용하는 편이 보통은 더 짧고 간결해, 람다로 작성할 코드를 새로운 메서드에 담은 다음, 람다 대신 그 메서드 참조를 사용하는 방식을 사용할 수 있다. 이때, 메서드 참조에 기능을 잘 드러내는 이름을 지어줄 수 있고, 주석으로 설명을 남길 수 있다. 메서드와 람다가 같은 클래스에 있을때는 람다가 메서드 참조보다 더 간결할 수 있다.

람다와 메서드가 모두 GoshThisClassNameIsHumonous 클래스에 있다면 람다로 구현한 것이 더 간결하고, 명확하다.

  • 메서드 참조

    service.execute(GoshThisClassNameIsHumonous::action);
  • 람다

    service.execute(() -> action());

메서드 참조 유형

유형

람다

정적

Integer::parseInt

str -> Integer.parseInt(str)

한정적(인스턴스)

Instant.now()::isAfter

Instant then = instant.now(); t -> then.isAfter(t);

비한정적(인스턴스)

String::toLowerCase

str -> str.toLowerCase()

클래스 생성자

TreeMap::new

() -> new TreeMap()

배열 생성자

int[]::new

len -> new int[len]

  • 수신 객체(참조 대상 인스턴스)를 특정하는 한정적 인스턴스 메서드 참조

    • 함수 객체가 받는 인수와 참조되는 메서드가 받는 인수가 동일

  • 수신 객체(참조 대상 인스턴스)를 특정하지 않는 비한정적 인스턴스 메서드 참조

    • 함수 객체를 적용하는 시점에 수신 객체를 알 수 있음

    • 수신 객체 전달용 매개변수가 매개변수 목록의 첫번째로 추가되며, 그 뒤로는 참조되는 메서드 선언에 정의된 매개변수들이 뒤따른다.

    • 주로, 스트림 파이프라인에서 매핑과 필터 함수에 주로 쓰임(Item 45)

정리하자면 다음과 같다. 메서드 참조가 더 짧고 명확하다면 메서드 참조를, 그렇지 않다면 람다를 사용하자.

Last updated