Item43. 람다보다는 메서드 참조를 사용하라!
- 람다가 익명 클래스보나 나은 점은 간결함!
- 그런데 자바엔 함수 객체를 람다보다 간결하게 만드는 방법이 있다?
- 그것은 바로 메서드 참조다.
람다, 메서드 참조 비교
1
2
3
4
// lambda
map.merge(key, 1, (count, incr) -> count + incr);
// method reference
map.merge(key, 1, Integer::sum);
- Map에 추가된 merge 메서드는 키, 값, 함수를 인수로 받는다.
- 주어진 키가 아직 없다면, [키,값] 쌍을 그대로 저장한다.
- 반대로 키가 이미 있다면, 함수를 현재 값과 주어진 값에 적용 후 그 결과를 덮어쓴다. [키, 함수(현재값, 주어진값)] 쌍 형태다.
- 주어진 예제에서 람다는 두 인수의 합을 단순 반환할 뿐이다.
- 이러한 경우 자바 8부터 제공되는 Integer 클래스의 정적 메서드인 sum을 이용하는 것이 간결함 유지에 더 도움이 된다.
간결함을 위해 메서드 참조를 사용하는 것이 좋으나, 매개변수 이름 자체가 프로그래머에게 좋은 가이드가 될 수 있는 경우 람다를 사용한다.
- 람다로 할 수 없는 일이라면 메서드 참조로도 할 수 없다.
- 람다로 작성할 코드를 새로운 메서드에 담은 다음, 람다 대신 그 메서드를 참조해 사용하는 방식이기 때문이다.
- 메서드 참조에는 기능을 잘 드러내는 이름을 지어줄 수 있다. 친절한 설명을 문서로 남길 수도 있다.
람다가 메서드 참조보다 간결한 경우
- 주로 메서드와 람다가 같은 클래스에 있을 때 그렇다.
예시
1
2
3
4
// 메서드 레퍼런스를 사용하는 경우
service.execute(GoshThisClassNameIsHumongous::action);
// 람다를 사용하는 경우
service.execute(() -> action());
- 코드가 GoshThisClassNameIsHumongous 클래스 안에 있는 경우
- 메서드 참조라고 해서 더 짧기도, 더 명확하지도 않다.
- 이러한 경우엔 람다를 사용하는 것이 더 좋다.
메서드 참조의 다섯 가지 유형
- 가장 흔한 유형은 앞의 예에서 본 것처럼 정적 메서드를 가리키는 메서드 참조다.
- 인스턴스를 참조하는 유형이 두 가지 있다.
- 수신 객체(참조 대상 인스턴스)를 특정하는 한정적(bound) 인스턴스 메서드 참조
- 함수가 받은 인수와 참조되는 메서드가 받는 인수가 같다.
- 수신 객체를 특정하지 않는 비한정적(unbound) 인스턴스 메서드 참조
- 함수 객체를 적용하는 시점에 수신 객체를 알려준다.
- 이를 위해 수신 객체 전달용 매개변수가 매개변수 첫 목록이 되고, 참조되는 선언에 사용되는 매개변수가 이를 뒤따른다.
- 수신 객체(참조 대상 인스턴스)를 특정하는 한정적(bound) 인스턴스 메서드 참조
- 생성자 참조가 있다. 생성자 참조는 팩터리 객체로 사용된다.
- 클래스 생성자를 가리키는 메서드 참조
- 배열 생성자를 가리키는 메서드 참조
메서드 참조 유형 | 예 | 같은 기능을 하는 람다 |
---|---|---|
정적 | Integer::parseInt | str -> Integer.parseInt(str) |
한정적 (인스턴스 참조) | Instant.now()::isAfter | Instant then = Instant.now(); t -> then.isAfter(t) |
비한정적 (인스턴스 참조) | String::toLowerCase | str -> str.toLowerCase() |
클래스 생성자 | TreeMap<K, V>::new | () -> new TreeMap<K,V>() |
배열 생성자 | int[]::new | len -> new int[len] |
핵심 정리
- 메서드 참조는 람다의 간단명료한 대안이 될 수 있다.
- 우선 메서드 참조 쪽을 고려한다.
- 람다와 비교했을 때, 람다로 표현한 것이 더 짧고 명확하다면 람다를 사용한다.
Comments powered by Disqus.