본문 바로가기
Dev Books/Effective Java

[item 30] 이왕이면 제네릭 메서드로 만들라.

by Thumper 2025. 2. 4.

클래스와 마찬가지로, 메서드도 제네릭으로 만들 수 있다.
로 타입과 제네릭 메서드의 차이점을 이해하고, 제네릭 메서드로 변환했을 때 타입 안정성을 갖는 이점을 이해해보자.

로 타입 사용

image
로(raw) 타입을 사용하고 있어 컴파일 시 경고가 발생한다.
로 타입은 제네릭 타입에서 타입 매개변수를 지정하지 않은 상태를 의미하며, 이는 타입 안전성을 저해하고 예상치 못한 오류를 유발할 수 있다.
따라서 제네릭 메서드로 변환하여 타입 안전성을 확보하는 것이 좋다.

제네릭 메서드로 변환된 코드

image
경고를 없애려면 위와 같이 타입 매개변수 목록을 , 반환타입을 Set으로 명시하면 된다.

✅ 제네릭 메서드 만들기

제네릭 메서드는 메서드 선언 시 타입 매개변수를 명시하여, 해당 메서드가 다양한 타입의 매개변수와 반환 타입을 처리할 수 있도록 한다.
예를 들어, Collections 클래스의 binarySearch나 sort와 같은 정적 유틸리티 메서드들이 제네릭 메서드로 구현되어 있다.
제네릭 메서드를 선언할 때는 리턴 타입 앞에 와 같은 타입 매개변수를 지정하고, 메서드 내부에서 이 타입 매개변수를 사용한다.

✔️ 예시

image
코드 union() 메서드는 집합 3개(입력 2개, 반환 1개)의 타입이 모두 같아야 한다.

제네릭 : 불변 객체를 여러 타입으로 활용할 수 있게 만드는 방법

불변 객체를 여러 타입으로 활용할 수 있게 만들어야 할 때가 있다.

제네릭 싱글턴 팩터리 패턴

불변객체가 제네릭 타입일 때 여러 타입으로 활용이 가능하다. 요청 타입 변수에 맞게 객체의 타입을 바꾸어주는 "제네릭 싱글턴 팩터리"가 필요하다.
예를 들어, Collections.reverseOrder 같은 함수객체가 있다.
image


Collections.reverseOrder는 제네릭 싱글턴 팩터리 패턴을 띄고있다.
image
ReverseComparator를 불변객체로 설계되어 있고, reverseOrder() 메서드의 반환타입은 제네릭 타입이므로 여러 타입으로 활용이 가능하다.
reverseComparator를 형변환하는 코드로, 요청 타입 변수에 맞게 객체의 타입을 바꾸어줄 수 있다.

✅ Function.identity()를 직접 구현해보기

이번에는 항등함수(identity function)를 담은 클래스를 만들어보자.
Function.identity()를 사용하면 되지만, 직접 구현하려면 다음과 같이 할 수 있다.
image

IDENTITY을 UnaryOperator<T>로 형변환하면 비검사 형변환 경고가 발생한다.
T가 어떤 타입이든 UnaryOperator<Object>UnaryOperator<T>가 아니기 때문이다.

하지만, 항등함수(identity function)는 입력값을 그대로 반환하는 함수다.
이 함수는 상태를 갖지 않으므로, 제네릭 싱글턴 방식으로 한 개의 인스턴스를 여러 타입에 대해 재사용할 수 있다.
어떤 타입이든 안전하므로, @SuppressWarning 애너테이션을 추가하여 경고 없이 컴파일되도록 숨겼다.

✔️ 예시

다음 코드는 제네릭 싱글턴을 UnaryOperator<String>UnaryOperator<Number>로 사용하는 모습이다.
image

image
형변환을 하지 않아도 컴파일 오류나 경고가 발생하지 않는다.

재귀적 타입 한정(recursive type)

재귀적 타입 한정은, 자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용범위를 한정할 수 있다.

Comparable 인터페이스

public interfave Comparable<T> {
  int compareTo(T o);
}

여기서 타입 매개변수 T는 Comparable<T>를 구현한 타입이 비교할 수 있는 원소 타입을 정의한다.

따라서 String은 Comparable<String>을 구현하고, Integer는 Comparable<Integer>를 구현하는 식이다.


✔️ 예시

컬렉션에서 최댓값을 반환한다. - 재귀적 타입 한정 사용

image
타입 한정인 <E extends Comparable<E>>는 "모든 타입 E는 자신과 비교할 수 있다."라고 읽을 수 있다.

컬렉션에 담긴 원소의 자연적 순서를 기준으로 최댓값을 계산하며, 컴파일 오류나 경고는 발생하지 않는다.
위의 sample 값에서 최댓갑인 "HI"가 출력된다.


image
이 메서드에 빈 컬렉션을 건넸기 때문에 IllegalArgumentException을 던진다.

결론

아래와 같은 경우에 재귀적 타입을 다루면 좋을 것 같다.

  • 반환값을 명시적으로 형변환해야 하는 메서드보다 제네릭 메서드가 훨씬 안전하고 사용하기도 쉽다.
  • 형변환은 좋지 않으니 제네릭 메서드를 사용할 수 있다면 무조건 제네릭 메서드를 사용하는 것이 좋다.

댓글