제네릭 메서드
매개변수화 타입을 받는 정적 유틸리티 메서드를 보통 제네릭 메서드라고 합니다.
- ex) Collections의 알고리즘 메서드인 binarySearch와 sort 메서드
제네릭 메서드 작성법
제네릭 메서드 작성법은 제네릭 타입 작성법과 비슷합니다.
메서드를 수정해 나가며 설명하겠습니다.
문제가 있는 메서드
위와 같이 메서드를 작성해도 컴파일은 정상적으로 되지만 타입 안전성을 보장할 수 없기 때문에 아이템 27에서 다루었던 비검사 경고가 발생합니다.
그리고 union 메서드를 통해 두 Set을 합치는 것까지는 문제가 발생하지 않지만 출력하는 과정에서 Integer 타입을 String 타입으로 형변환하는 과정에서 ClassCastException이 발생합니다.
따라서 union 메서드는 동일한 타입의 Set들을 합친다는 것을 보장해야 하고 이를 위해 메서드 선언에서의 세 집합(입력 2개, 반환 1개)의 원소 타입을 타입 매개변수로 명시하고, 메서드 내에서도 해당 타입 매개변수만 사용하도록 수정해야 합니다.
제네릭 메서드
제네릭 메서드로 선언하면 타입 안전성을 보장하기 때문에 비검사 경고 없이 컴파일이 되며 사용하기도 용이합니다.
간단한 제네릭 메서드라면 이 정도로도 충분하지만 아이템 31에서 다룰 한정적 와일드카드 타입을 사용하면 보다 유연하게 개선시킬 수 있습니다.
제네릭 싱글턴 팩터리
제네릭은 런타임에 타입 정보가 소거되므로 하나의 객체를 어떤 타입으로든 매개변수화할 수 있습니다.
이렇게 하려면 요청한 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리를 생성해야 하며 이 패턴을 제네릭 싱글턴 팩터리라고 합니다.
- 제네릭으로 타입 설정 가능한 인스턴스를 생성해두고 반환 시에 제네릭으로 받은 타입을 이용해 타입을 결정
- ex) Collections.reverseOrder, Collections.emptySet
자기 자신을 반환하는 항등함수를 예로 설명해 보겠습니다.
제네릭 싱글턴 팩터리 패턴을 적용하지 않을 경우 아래 코드처럼 타입별로 identity 메서드를 만들어줘야 할 것입니다.
반면 제네릭은 런타임에 타입이 소거되기 때문에 제네릭 싱글턴 메서드 하나로도 모든 타입을 대처할 수 있습니다.
재귀적 타입 한정
드물지만 자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정 지을 수 있으며 이를 재귀적 타입 한정(recursive type bound)라고 합니다.
재귀적 타입 한정은 주로 타입의 자연적 순서를 정하는 Comparable 인터페이스와 함께 쓰입니다.
여기서 타입 매개변수 T는 Comparable<T>를 구현한 타입이 비교할 수 있는 원소의 타입을 정의하며 실제로 거의 모든 타입은 자신과 같은 타입의 원소와만 비교할 수 있습니다.
- String은 Comparable<String>을 구현
- Integer는 Comparable<Integer>를 구현
Comparable을 구현한 원소의 컬렉션을 입력받는 메서드들은 주로 그 원소들을 정렬 혹은 검색하거나, 최솟값이나 최댓값을 구하는 식으로 사용되며 해당 기능을 수행하려면 컬렉션에 담긴 모든 원소가 상호 비교될 수 있어야 합니다.
다음은 재귀적 타입 한정을 이용하여 컬렉션에 담긴 원소의 자연적 순서를 기준으로 최댓값을 계산하는 코드입니다.
위 코드에서 타입 한정인 <E extends Comparable<E>>를 해석하면 아래와 같습니다.
- 모든 타입 E는 자신과 비교할 수 있다
- 상호 비교 가능하다는 뜻을 아주 정확하게 표현
실제로는 Collection 라이브러리를 직접 수정하지 않는 이상, 위와 같은 기능을 구현할 필요가 거의 없을 것입니다.
하지만 재귀적 타입 한정은 Collection 뿐만 아니라 아이템 2에서 다루었던 추상 클래스 Builder에도 사용되기 때문에 알아두면 좋습니다.
정리
제네릭 타입과 마찬가지로 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메서드보다 제네릭 메서드가 더 안전하며 사용하기도 용이합니다.
따라서 귀찮더라도 타입과 마찬가지로 형변환을 해줘야 하는 기존 메서드를 제네릭하게 변환하는 것을 권장합니다.
참고
이펙티브 자바
이펙티브 자바 완벽 공략 2부 - 백기선 강사님
'JAVA > Effective Java' 카테고리의 다른 글
[아이템 32] 제네릭과 가변인수를 함께 쓸 때는 신중하라 (0) | 2024.02.22 |
---|---|
[아이템 31] 한정적 와일드카드를 사용해 API 유연성을 높이라 (2) | 2024.02.21 |
[아이템 29] 이왕이면 제네릭 타입으로 만들라 (6) | 2024.02.19 |
[아이템 28] 배열보다는 리스트를 사용하라 (1) | 2024.02.18 |
[아이템 27] 비검사 경고를 제거하라 (1) | 2024.02.16 |