티스토리 뷰
Item43에서는 람다보다 메서드 참조를 사용하라 말한다
메서드 참조를 사용하는 이유는 간결함 때문이다
람다를 사용해 익명 함수를 대체하고 간결하게 표현하기로 한 거 끝까지 가보자는 것이다
메서드 참조를 사용하는 방법은 네 가지가 있다
1. static method reference
<클래스::정적 메서드> 형태로 참조한다
2. instance method reference (bound receiver)
<인스턴스::인스턴스 메서드> 형태로 참조한다
3. instance method reference (unbound receiver)
<특정 타입의 아무 인스턴스::인스턴스> 메서드 형태로 참조한다
4. constructor reference
<클래스::new> 연산자 형태로 참조한다
이 중 한정적과 비한정적의 차이가 확 와닿지 않아서 좀 더 찾아봤다
책에서는 수신 객체를 특정하느냐 아니냐로 한정적과 비한정적 메서드 참조를 설명한다
한정적 메서드 참조를 설명할 때 Instance.now()::isAfter를 예시로 드는데 이것 땜시 헷갈렸다
아래의 글에서는 조금 더 직접적으로 설명하는데
메서드 참조를 하는 시점에 메서드를 참조할 외부 인스턴스가 존재하고 있느냐 아니냐로 나눌 수 있다
bound 한정적이라는 것은 외부 인스턴스가 이미 존재하고 있어야 함을 의미하고
unbound 비한정적이라는 것은 외부 인스턴스는 없어도 되고 참조하는 시점에만 인스턴스가 존재하면 된다는 것을 의미한다
쉽게 말해 한정적 메서드 참조는 이미 존재하는 인스턴스의 메서드를 참조하는 것이다
이미 존재하는 인스턴스의 메서드에 묶여 있으니 bound, 한정적이라는 명칭을 붙인 것 같다
스트림으로 돌릴 때 돌아가는 요소의 타입은 알고 있지만 인스턴스의 값은 알지 못 하는 상태다
그러니 특정 타입인 것만 알고 어떤 인스턴스가 와도 무방하니 이를 비한정적 메서드 참조라 하는 것이다
아래 코드 예시로 보면 스트림으로 돌릴 때 Bicycle 타입인 것을 알고 있으니
Bicycle::getBrand, Bicycle::getFrameSize는 비한정적 메서드 참조이고 어떤 Bicycle 인스턴스에도 적용할 수 있다
bicycle3 인스턴스의 메서드를 참조할 때는 이미 존재하는 bicycle3에 묶여 있는 상태로 참조하니 한정적 메서드 참조다
미묘한 차이라 반복 설명을 하게 되는데 사실 이렇게까지 알 필요는 없을 듯 하다, 어차피 IDE가 친절히 알려줄 것이다
한정적, 비한정적 메서드 참조로 아직 호되게 당해본 적이 없어서 그럴 수도 있지만..?
Bicycle bicycle1 = new Bicycle("panda", 55);
Bicycle bicycle2 = new Bicycle("bear", 66);
// unbound method reference
List<String> strings = bicycles.stream()
.map(Bicycle::getYaho)
.toList();
// bound method reference
Bicycle bicycle3 = new Bicycle("yahoo", 77);
List<String> strings = bicycles.stream()
.map(bicycle3::getYaho)
.toList();
더 궁금하다면 Bicycle 예제 코드를 보면서 직접 메서드 참조를 사용해보자
public class MethodReferenceExample {
public static void main(String[] args) {
Bicycle bicycle1 = new Bicycle("panda", 55);
Bicycle bicycle2 = new Bicycle("bear", 66);
List<Bicycle> bicycles = List.of(bicycle1, bicycle2);
BicycleComparator bicycleComparator = new BicycleComparator();
List<Bicycle> sortedBicycles = bicycles.stream()
.sorted(bicycleComparator::compare)
.toList();
System.out.println("sortedBicycles = " + sortedBicycles);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Bicycle {
private String brand;
private Integer frameSize;
}
public static class BicycleComparator implements Comparator<Bicycle> {
@Override
public int compare(Bicycle o1, Bicycle o2) {
return o1.getFrameSize().compareTo(o2.getFrameSize());
}
}
}
자바 17과 친해지고 싶어 이펙티브 자바를 17로 공부 중인데
인텔리제이가 bicycleCompartor::compare를 bicycleCompartor로 바꾸라 알려준다
자바 17에서는 compare 마저 줄일 수 있는 건가?! 싶어서 자바 8로 바꿔봤는데도 여전히 알려주는 것으로 보아
새로 들어온 기능은 아니고 Comparator가 compare만 가지고 있는 @FunctionalInterface라 그런 것 같다
끝으로 다양한 메서드 참조를 써보면서 느낀 점은 아이템43의 조언은 깡그리 무시하고 람다로 다 발라놔도 무방하다는 점이다
간결한 표현을 위해 메서드 참조를 사용하는 것인데 이에 따른 단점으로는 메서드 시그니처를 알고 있어야 한다는 것이다
메서드 참조를 사용하면 표현은 더 간결해질지 몰라도 <클래스명 또는 인스턴스명::메서드 이름>만 덩그러니 있게 된다
따라서 Integer::sum, String::toUpperCase 같은 건 직관적이니 쉽게 알 수 있어도
직접 만든 메서드의 경우엔 어떤 작용을 하는지 메서드 내부로 들어가봐야 알 수 있다
게다가 작성한 본인은 메서드 참조를 쉽게 파악할 수 있어도 남이 볼 땐 아닐 수 있다
간결함과 이해 용이성의 트레이드오프니 익숙해지면 메서드 참조로 하고 이것 저것 따지기 귀찮으면 람다로 다 발라놓자
'Java > Effective Java' 카테고리의 다른 글
[Item45] Stream vs For-Loop (0) | 2022.04.05 |
---|---|
[Item44] 바퀴를 재발명 하지 말자 (0) | 2022.04.02 |
[Item42] 람다 쓰자! (0) | 2022.03.28 |
[Item41] 마커 인터페이스 vs 마커 애노테이션 (0) | 2022.03.26 |
[Item40] 긴가 민가 할 땐 붙여라 (0) | 2022.03.24 |