[Effective Java] 이왕이면 제네릭 메소드로 만들라

들어가며

제네릭 타입과 마찬가지로, 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메소드보다 제네릭 메소드가 더 안전하며 사용하기도 쉽다. 타입과 마찬가지로, 메소드도 형변환 없이 사용할 수 있는 편이 좋으며, 많은 경우 그렇게 하려면 제네릭 메소드가 되어야 한다. 역시 타입과 마찬가지로 형변환을 해줘야 하는 기존 메소드는 제네릭하게 만들자.

매개변수화 타입을 받는 정적 유틸리티 메소드는 보통 제네릭이다. 다음은 두 집합의 합집합을 반환하는 문제가 있는 메소드이다.

1
2
3
4
5
public static Set union(Set s1, Set s2) {
Set result = new HashSet(s1);
result.addAll(s2);
retun result;
}

위 메소드는 타입 안전하지 않은 메소드이기 때문에 이를 타입 안전하게 만들어야 한다.

1
2
3
4
5
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}

제네릭 싱글톤 팩터리 패턴

때로는 불변 객체를 여러 타입으로 활용할 수 있게 만들어야 할 때가 있다. 제네릭은 런타임에 타입 정보가 소거되므로 하나의 객체를 어떤 타입으로든 매개변수화할 수 있다. 하지만 이렇게 하려면 요청한 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리를 만들어야 한다. 이를 제네릭 싱글톤 팩터리 패턴이라 한다. 다음 항등함수(identity function)에 대한 코드를 보자.

1
2
3
4
5
6
private static UnaryOperator<Object> IDENTIFY_FN = (t) -> t;

@SuppressWarnings("unchecked")
public static<T> UnaryOperator<T> identityFunction() {
return (UnaryOperator<T>) IDENTIFY_FN;
}

항등함수객체는 무상태이니 요청마다 매번 새로 만드는 것은 낭비다. 그리고 타입별로 하나씩 만들어야 했겠지만 소거 방식을 사용한 덕에 제네릭 싱글턴 하나면 충분하다. 이 코드는 비검사 형변환 경고가 발생하지만 항등함수는 언제나 같은 값을 반환하는 특별한 함수이므로 (unaryOperator\)를 사용해도 타입 안전하다. 그러니 @SuppressWarnings로 경고를 숨겨도 안심할 수 있다.

재귀적 타입 한정

재귀적 타입 한정은 자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정하는 것이다. 이는 주로 타입의 자연적 순서를 정하는 Comparable 인터페이스와 함께 쓰인다. 여기서 Comparable\을 통해 자기 자신과 같은 타입의 원소와 비교가 가능하다. 다음 코드를 보자.

1
public static <E extends Comparable<E>> E max(Collection<E> c);

위 코드는 타입 한정을 사용하여 자신의 타입과 상호 비교가 가능하다는 뜻을 표현하고 있다. 이를 구현한 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
public static <E extends Comparable<E>> E max(Collection<E> c) {
if (c.isEmpty())
throw new IllegalArgumentException("Empty Collection");

E result = null;
for (E e : c)
if (result == null || e.compareTo(result) > 0)
result = Objects.requireNonNull(e);

return result;
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/11/Languages/Effective%20JAVA/item30/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.