지난 번 글에서 Java 8 에서 등장한 람다 표현식에 대해 정리했다.
오늘은 두번재로 메서드 참조에 대해 알아보자.
버전 |
기능 | 종류 | 설명 |
8 | Lambda Expression 및 Method Reference 도입 |
Language | anonymous inner class 표현 간략화 (함수형 표현) 인자로 method reference를 전달 (함수형 표현) |
8 | Collections & Streams | Language | Collections에서 Streams API를 사용하여, 이전의 반복문이 아닌 함수형 구현 |
8 | Interface Default Method 도입 | Language | interface 내부에서 default 메서드를 선언할 수 있다. |
8 | Optional Class 도입 | Language | Optional Class를 이용하여 NullPointerException이 발생하는 것을 방지해 준다. |
메서드 레퍼런스의 정의
메소드 레퍼런스(method reference)는 기존의 메서드를 정의를 활용해서 람다처럼 전달할 수 있다.
때로는 람다표현식보다 메서드 레퍼런스를 이용하는 것이 더 가독성이 좋고 자연스러울 때가 있다.
아래의 예를 보면 확실히 알 수 있다.
어떤 기능을 하는 메서드인지 확실히 눈에 들어온다.
// 기존 람다식으로 표현한 메서드
inventory.sort((Apple a, Apple b) ->
a.getWeight().compareTo(b.getWeight());
// 메서드 레퍼런스를 활용한 코드
inventory.sort(comparing(Apple::getWeight));
그렇다면, 메서드 레퍼런스가 왜 중요할까?
메서드 레퍼런스는 특정 메서드만을 호출하는 람다의 축약형이라고 볼 수 있다.
람다가 이 메서드를 호출해라고 했을 때 메서드를 어떻게 호출하는지 표현하는 것보다 메서드 명을 참조하는 것이 나을 때가 있다.
실제로 메서드 레퍼런스는 기존 메서드 구현으로 람다 표현식을 만들 수 있다.
이때 명시적으로 메서드명을 참조하게 되고 가독성을 높일 수 있다.
결과적으로 위의 Apple::getWeight은 (Apple a) -> a.getWeight() 를 축약한 것과 같다.
메서드 레퍼런스 문법
메소드 참조를 사용하면 불필요한 매개변수를 제거하고 다음과 같이 '::' 기호를 사용하여 표현할 수 있다.
클래스 이름으로 바로 메소드를 호출하거나, 참조 변수 이름으로 메소드를 호출하는 방식이다.
실제 메서드를 호출하는 것은 아니기 때문에 괄호가 없다는 것을 기억하자.
클래스이름::메소드이름
or
참조변수이름::메소드이름
다양하게 사용되는 람다와 메서드 레퍼런스 단축 예제
람다 | 메서드 레퍼런스 |
(Apple a) -> a.getWeight() | Apple::getWeight |
() -> Thread.currentThread().dumpStack() | Thread.currentThread()::dumpStack |
(str, i) -> str.substring(i) | String::substring |
(String s) -> System.out.println(s) | System.out::println |
메서드 레퍼런스 종류
static 메서드 레퍼런스
ex) Integer의 parseInt 메서드는 Integer::parseInt로도 표현 가능하다.
인스턴스 메서드 레퍼런스
ex) String 의 length 메서드는 String::length 로 표현 가능하다.
참조 변수 메서드 레퍼런스
ex) Transaction 객체를 할당받은 expensiveTransaction 지역변수가 있고, Transaction 객체에는 getValue 메서드가 있다면
이를 expensiveTransaction::getValue 라고도 표현할 수 있다.