들어가며
Java 8 이상에서 람다식을 사용할 때 콜론 2개를 사용하는 경우가 있습니다. 이를 메서드 참조(Method Reference) 혹은 이중 콜론 연산자(::)라고 표현하는데요. 정식 명칭은 메서드 참조입니다. 그러면 메서드 참조는 어떨 때 사용할 수 있는 것인지, 그리고 어떻게 사용하는 것인지 간단하게 알아보겠습니다.
메서드 참조는 언제, 어떻게 사용할 수 있을까
메서드 참조는 람다식에서 파라미터의 중복을 피하기 위해 사용합니다. 파라미터가 중복되지 않았다면 메서드 참조 표현식은 사용 불가능합니다. 코드로 바로 보겠습니다.
인스턴스의 메서드를 참조하는 경우
public class Main {
public static void main(String[] args) {
List<Member> memberList = Arrays.asList(new Member("A"), new Member("B"), new Member("C"));
String collect = memberList.stream().map(element -> element.getName()).collect(Collectors.joining());
System.out.println(collect);
}
public static class Member {
private String name;
public Member(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
위 코드에서 stream 생성 이후 map 메서드에서 람다식을 사용했습니다. 이때 map에 걸리는 요소들은 Member 인스턴스죠. 그리고 map 내부에서 인스턴스의 메서드인 getName()을 호출하고 있습니다.
그런데 문제는 요소를 지칭하는 element가 두 번이나 등장합니다. Java에서는 이게 보기 싫었던 겁니다. 이걸 꼭 한 번만 써주고 싶었던 것이죠. 위 코드에서 람다식을 메서드 참조 표현식으로 변경해보면 다음과 같습니다.
// 일반 람다식
String collect = memberList.stream().map(element -> element.getName()).collect(Collectors.joining());
// 메서드 참조 표현식
String collect = memberList.stream().map(Member::getName).collect(Collectors.joining());
위 코드에서 메서드 참조 표현식의 사용 형태는 다음과 같습니다.
// 일반 람다식
(인스턴스 -> 인스턴스.메서드명)
// 메서드 참조 표현식
(인스턴스의 클래스명::메서드명)
인스턴스를 생성하는 경우
public class Main {
public static void main(String[] args) {
List<String> memberNameList = List.of("A", "B", "C");
List<Member> memberList = memberNameList.stream().map(name -> new Member(name)).collect(Collectors.toList());
memberList.forEach(member -> System.out.println(member.getName()));
}
public static class Member {
private String name;
public Member(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
위 코드에서 memberList를 초기화할 때 stream 생성 이후 map 메서드에서 람다식을 사용했습니다. 이때 map에 걸리는 요소들은 String 객체지만, Member 클래스의 인스턴스를 만들 때 인자로 들어갑니다. 이때도 메서드 참조 표현식이 가능합니다. 위 코드에서 람다식을 메서드 참조 표현식으로 변경해보면 다음과 같습니다.
// 일반 람다식
List<Member> memberList = memberNameList.stream().map(name -> new Member(name)).collect(Collectors.toList());
// 메서드 참조 표현식
List<Member> memberList = memberNameList.stream().map(Member::new).collect(Collectors.toList());
위 코드에서 메서드 참조 표현식의 사용 형태는 다음과 같습니다. 특히, 이렇게 메서드가 아닌 생성자를 참조할 때는 생성자 참조 표현식이라고 부릅니다.
// 일반 람다식
(인자로 들어갈 객체 -> new 클래스명(인자로 들어갈 객체))
// 메서드 참조 표현식
(클래스명::new)
결론
람다식을 이용할 때 메서드 참조 표현식을 사용하면 간결해질 수 있다는 장점이 있지만, 람다식 혹은 메서드 참조 표현식에 익숙하지 않은 동료와 함께 개발한다면 오히려 가독성을 해칠 수 있다는 우려도 있습니다. 간결한 것도 좋지만 동료와 컨벤션을 맞추어 모두에게 가독성이 좋은 개발하는 것이 최고라고 생각합니다.
참고로 위에 보여드린 예시는 정말 일부일 뿐이며, IntelliJ를 사용하신다면 IntelliJ가 메서드 참조 표현식을 사용할 수 있을 때 해당 부분을 하이라이트 처리해준 후 메시지를 띄워줍니다. 그러니 이런 사소한 것까지 외우기보다는 이런 표현 방식도 있구나 정도로 이해해주시면 될 것 같습니다.
'Dev > Java' 카테고리의 다른 글
[Java] 배열(Array) vs. 배열리스트(ArrayList) vs. 연결리스트(LinkedList) (2) | 2021.03.30 |
---|---|
[Java] gradle 환경에서 JMH를 사용하여 벤치마킹하기 (0) | 2021.03.22 |
[Java] 객체와 클래스, 인스턴스 간 차이 (4) | 2021.03.10 |