람다가 익명 클래스보다 나은 점 중 가장 큰 특징은 간결함이다. 하지만 메서드 참조는 람다보다 코드를 더 간결하게 만들 수 있다.
map.merge(key, 1, (count, incr) -> count + incr);
위의 코드는 key가 map안에 없다면, key와 숫자 1을 매핑하고 이미 있다면 기존 매핑 값을 증가시킨다. 이 코드에서 매개변수 count와 incr은 크게 하는 일 없이(두 인수의 합 반환) 공간을 꽤 차지 않다. 따라서 아래와 같이 메서드 참조를 사용할 수 있다.
map.merge(key, 1, Integer::sum);
하지만 매개변수의 이름 자체가 프로그래머에게 좋은 가이드가 될 땐 길이가 길어도 유지보수를 위해 람다를 사용하는게 좋을 수 잇다.
람다로 할 수 없는 일이라면 메서드 참조로도 할 수 없다. 따라서 람다로 구현했는데, 너무 길다면 메서드 참조는 좋은 대안이 된다. 람다로 작성할 코드를 새로운 메서드에 담은 다음, 람다 대신 그 메서드 참조를 사용하는 방식을 사용하는 것이다. 메서드 참조에는 기능을 잘 드러내는 이름을 지어줄 수 있고 친절한 설명을 문서로 남길 수 있다.
service.execute(GoshThisClassNameIsHumongous::action);
위의 GoshThisClassNameIsHumongous 클래스의 코드는 아래와 같이 람다로 대체될 수 있다.
service.execute(() -> action());
메서드 참조를 사용한 코드가 더 짧지도, 명확하지도 않다. 따라서 이 경우엔 람다가 낫다.
메서드 참조의 유형은 다섯 가지로, 가장 흔한 유형은 위에서 알아본 정적 메서드를 가리키는 메서드 참조다. 나머지 네가지 참조를 알아보자.
근본적으로 정적 참조와 비슷해 함수 객체가 받는 인수와 참조되는 메서드가 받는 인수가 똑같다.
함수 객체를 적용하는 시점에 수신 객체를 알려준다. 이를 위해 수신 객체 전달용 매개변수가 매개변수 목록의 첫번째로 추가되며, 그 뒤로는 참조되는 메서드 선언에 정의된 매개변수들이 뒤따른다.
주고 스트림 파이프라인에서의 매핑과 필터함수에 쓰인다.
생성자 참조는 팩터리 객체로 사용된다.
메서드 참조 유형 | 예 | 같은 기능을 하는 람다 |
---|---|---|
정적 | Integer::parseInt | str -> Integer.parseInt(str) |
한정적(인스턴스) | Instance.now()::isAfter | Instance then = Instant.now(); t -> then.isAfter |
비한정적(인스턴스) | String::toLowerCase | str ->s tr.strtoLowerCase(); |
클래스 생성자 | TreeMap<K,V>::new | ()->new TreeMap<K,V>() |
배열 생성자 | int[]::new | len -> new int[len]; |
이펙티브 자바 3/E
이펙티브 자바 github