책/이펙티브 자바

item 43 람다보다는 메서드 참조를 사용하라

함께자라기 2022. 4. 11. 16:17

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


메서드 참조

람다가 익명 클래스보다 좋은점 중 가장 큰 특징은 간결함인데 함수 객체를 람다보다도 간결하게 만드는 방법이다

임의의 키와 Integer 값의 매핑을 관리하는 프로그램의 일부


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

값이 키의 인스턴스 개수로 해석된다면 멀티셋을 구현한게 된다

위 코드는 깔끔하게 보이지만 매개변수 count와 incr이 하는일 없이 공간을 차지한다

위 람다는 두 인수의 합을 단순히 반환할 뿐인데 java8의 Integer 등 기본타입의 박싱 타입은 같은 기능을 하는 sum 메서드를 제공하기 때문에 아래와 같이 코드로 변경 가능하다

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

메서드 참조를 사용했더니 같은 동작을 하지만 코드가 훨씬 보기 좋아졌다

매개변수의 수가 늘어날수록 메서드 참조로 제거할 수 있는 코드양도 늘어난다

하지만 모든 람다를 메서드 참조로 바꿔야 되는건 아니다

  • 어떤 람다는 매개변수의 이름 자체가 가독성을 높이는 경우도 있으며 이런 경우는 메서드 참조보다 길지만 읽기 쉬우며 유지보수도 편리하다
  • 가끔 람다가 메서드 참조보다 간결한 경우도 있는데 메서드와 람다가 같은 클래스에 있는 경우다
아래의 코드가 GoshThisClassNameIsHumongous 클래스 안에 있다면...

service.execute(GoshThisClassNameIsHumongous::action);

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

위 코드는 메서드 참조가 더 짧지도 않고 명확하지도 않다

이런 경우 람다로 구현하는게 더 좋다

또한 대부분 람다로 할 수 없는 일은 메서드 참조로도 할 수 없지만 함수형 인터페이스를 위한 제네릭 함수 타입은 메서드 참조 표현식으로 구현 가능하며 람다로는 불가능하다

  • 제네릭 람다식이라는 문법이 없다

하지만 대부분 메서드 참조를 사용하는 경우 코드의 가독성이 많이 올라가니 람다로 구현했는데 너무 길거나 복잡하면 메서드 참조를 고려하자

  • 람다로 작성할 코드를 새로운 메서드에 담고 람다 대신 그 메서드 참조를 사용
  • 메서드 참조에는 기능을 잘 나타내는 이름을 지어줄 수 있고 설명을 문서로 남길 수 있다

메서드 참조 유형 다섯가지

  • 정적 메서드를 가리키는 메서드 참조
  • 인스턴스 메서드를 참조하는 유형 두가지
    • 수신 객체(receiving object 참조 대상 인스턴스)를 특정하는 한정적(bound) 인스턴스 메서드 참조
      • 한정적 참조는 근본적으로 정적 참조와 비슷하다
      • 함수 객체가 받는 인수와 참조되는 메서드가 받는 인수가 똑같다
    • 수신 객체를 특정하지 않는 비한정적(unbound) 인스턴스 메서드 참조
      • 비한정적 참조에서는 함수 객체를 적용하는 시점에 수신 객체를 알려준다
      • 이를 위해 수신 객체 전달용 매개변수가 매개변수 목록의 첫 번째로 추가되고 그 뒤로는 참조되는 메서드 선언에 정의된 매개변수들이 뒤따른다
      • 주로 스트림 파이프라인에서의 매핑과 필터 함수에 사용된다
  • 클래스 생성자를 가리키는 메서드 참조
  • 배열 생성자를 가리키는 메서드 참조
    • 생성자 참조는 팩터리 객체로 사용된다

메서드 참조는 람다의 간단명료한 대안이 될 수 있다

메서드 참조 쪽이 짧고 명확하다면 메서드 참조를 쓰고, 그렇지 않을 때만 람다를 사용하자