티스토리 뷰
(Effective Java) 규칙43. 람다보다는 메서드 참조를 사용하라
람다
-
람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함인데 람다보다도 더 간결하게 만들 수 있는 방법이 있다.
- 바로 메서드 참조(method reference) 임
-
예) 임의의 키와
Integer
값의 매핑을 관리하는 프로그램- 값이 키의 인스턴스 개수로 해석된다면, 이 프로그램은 멀티셋(multiset)을 구현한게 됨
- 키가 맵 안에 없다면 키와 숫자1을 매핑하고, 이미 있다면 기존 매핑 값을 증가시킴
map.merge(key, 1, (count, incr) -> count + incr);
- 자바 8때
Map
에 추가된merge
메서드, 키, 값, 함수를 인수로 받아 수행하는 함수임
- 자바 8때
메서드 참조
-
위 코드는 깔끔한 코드지만
count
와incr
은 크게 할 일 없이 공간을 꽤 차지 함- 람다는 두 인수의 합을 단순히 반환할 뿐임
- 자바 8이 되면서
Integer
클래스(와 모든 기본 타입의 박싱 타입)는 이 람다와 기능이 같은 정적 메서드sum
을 제공하기 시작함
-
위 코드에 람다 대신에
sum
메서드 참조를 전달하면 똑같은 결과를 더 보기 좋게 얻을 수 있다.map.merge(key, 1, Integer::sum);
- 매개변수가 늘어날수록 메서드 참조로 제거할 수 있는 코드양도 늘어남
-
단, 매개변수 자체가 의미가 있는 경우는 람다가 더 읽기 쉽고 유지보수도 쉬울 수 있음
람다, 메서드 참조의 사용
-
람다로 할 수 없는 일이라면 메서드 참조로도 할 수 없다. (애매한 예외가 하나 있는데, 마지막에 보충 설명 참고)
-
메서드 참조를 사용하는 편이 보통은 더 짧고 간결하므로, 람다로 구현했을 때 너무 길거나 복잡하다면 메서드 참조가 좋은 대안이 되어준다.
- 즉, 람다로 작성할 코드를 새로운 메서드에 담은 다음, 람다 대신 그 메서드참조를 사용하는 식
- 메서드 참조에 기능을 잘 드러내는 이름을 지어줄 수도 있고 설명을 문서로 남길 수도 있음
-
다만, 항상 메서드 참조가 적절한 것은 아니다.
- 예) 참조할 메서드가
GoshThisClassNameIsHumongous
클래스 안에 있다고 할 때//메서드 참조를 할 때 service.execute(GoshThisClassNameIsHumongous::action); //람다 사용을 할 때 service.execute(() -> acation());
- 예)
java.util.function
패키지의 제네릭 정적 팩터리 메서드인Function.identity()
를 사용하기보다는 똑같은 기능의 람다(x -> x)
를 직접 사용하는 게 더 짧고 명확함
- 예) 참조할 메서드가
메서드 참조 유형
메서드 참조 정리표
메서드 참조 유형 | 예 | 같은 기능을 하는 람다 |
정적 | 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] |
유형 분류
-
정적 메서드를 가리키는 참조
- 앞에서 본 유형으로 가장 흔한 유형
-
인스턴스 메서드를 참조하는 유형
- 수신 객체(receiving object; 참조 대상 인스턴스)를 특정하는 한정적(bound) 인스턴스 메서드 참조
- 정적 참조와 비슷하며 함수 객체가 받는 인수와 참조되는 메서드가 받는 인수가 똑같음
- 수신 객체를 특정하지 않는 비한정적(unbound) 인스턴스 메서드 참조
- 함수 객체를 적용하는 시점에 수신 객체를 알려줌
- 수신 객체 전달용 매개변수가 매개변수 목록의 첫번째로 추가되며, 그 뒤로는 참조되는 메서드 선언에 정의된 매개변수들이 뒤따름
- 주로 스트림 파이프라인에서의 매핑과 필터 함수에 쓰임
- 수신 객체(receiving object; 참조 대상 인스턴스)를 특정하는 한정적(bound) 인스턴스 메서드 참조
-
생성자를 가리키는 참조 (주로 팩터리 객체로 사용됨)
- 클래스 생성자를 가리키는 참조
- 배열 생성자를 가리키는 참조
결론
-
메서드 참조는 람다의 간단명료한 대안이 될 수 있다.
-
메서드 참조 쪽이 짧고 명확하다면 메서드 참조를 쓰고, 그렇지 않을 때만 람다를 사용하라.
보충 설명
-
람다로는 불가능하나 메서드 참조로는 가능한 유일한 예는 바로 제네릭 함수 타입(generic function type) 구현이다.
자바 명세의 예제 9.9-2(http://bit.ly/2uYQnbh)를 번역한 글
- 함수형 인터페이스의 추상 메서드가 제네릭일 수 있듯이 함수 타입도 제네릭일 수 있다. 다음의 인터페이스 계층구조를 생각해보자.
interface G1 { <E extends Exception> Object m() throws E; } interface G2 { <F extends Exception> String m() throws Exception; } interfacea G extends G1, G2 {}
- 이때 함수형 인터페이스 G를 함수 타입으로 표현하면 다음과 같다.
<F extends Exception> () -> String throws F
- 이처럼 함수형 인터페이스를 위한 제네릭 함수 타입은 메서드 참조 표현식으로는 구현할 수 있지만, 람다식으로는 불가능하다.
- 제네릭 람다식이라는 문법이 존재하지 않기 때문이다.
끝으로
이 글이 도움이 되었다면, 하단의 Google 광고 👎👎👎 한번씩 클릭 부탁 드립니다. 🙏🙏🙏
광고 클릭은 많은 힘이 됩니다!
반응형
'프로그래밍 > EffectiveJava' 카테고리의 다른 글
(이펙티브 자바) 규칙 62. 다른 타입이 적절하다면 문자열 사용을 피하라 (0) | 2020.03.10 |
---|---|
(이펙티브 자바) 규칙77. 예외를 무시하지 말라 (0) | 2020.03.09 |
(이펙티브 자바) 규칙45. 스트림은 주의해서 사용하라 (0) | 2020.03.05 |
(이펙티브 자바) 규칙15. 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2020.03.03 |
(이펙티브 자바) 규칙 60. 정확한 답이 필요하다면 float과 double은 피하라 (0) | 2020.03.02 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- JavaFX Table View
- 이펙티브
- JavaFX 종료
- 방통대 과제물
- 자전거 여행
- JavaFX
- windows
- 인텔리제이
- 스프링부트
- effectivejava
- 일본여행
- java
- 자전거
- git
- 이펙티브 자바
- TableView
- intelij
- 일본 자전거 여행
- 배낭여행
- 일본 여행
- 이펙티브자바
- JavaFX 테이블뷰
- Java UI
- effective java
- 배낭 여행
- 자바
- 일본 배낭여행
- 텐트
- springboot
- JavaFX Window Close
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함