아이템30. 이왕이면 제네릭 메서드로 만들라

wisdom·2022년 8월 19일
0

Effetctive Java

목록 보기
30/80
post-thumbnail

클래스와 마찬가지로 메서드도 제네릭으로 만들 수 있다.

✔️ 단순한 제네릭 메서드

두 집합의 합집합을 반환하는 메서드를 예시로 보자.

로 타입 사용

public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    return result;
}

위의 코드는 컴파일은 되지만 경고가 두 개 발생한다. 경고를 없애기 위해서는, 메서드를 타입 안전하게 만들어야 한다.

세 집합(입력 2개, 반환 1개)의 원소 타입을 타입 매개변수로 명시하고, 메서드 안에서도 이 타입 매개변수만 사용하게 수정하자!

제네릭 메서드

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

이 메서드는 경고 없이 컴파일되며, 타입 안전하고, 쓰기도 쉽다!

✔️ 제네릭 싱글턴 팩터리 패턴

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

제네릭은 런타임에 타입 정보가 소거되므로 하나의 객체를 어떤 타입으로든 매개변수화할 수 있다.

하지만 이렇게 하려면, 제네릭 싱글턴 팩터리라고 하는 패턴을 사용하여야 한다.

💡 제네릭 싱글턴 팩터리

요청한 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리

이번엔 항등함수를 담은 클래스를 다음과 같이 만들어보자.

타입별로 하나씩 만들 필요 없이 제네릭 싱글턴 하나면 충분하다.

 private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;

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

✔️ 재귀적 타입 한정 (Recursive type bound)

상대적으로 드물긴 하지만 재귀적 타입 한정이라는 개념을 사용할 수도 있다.

💡 재귀적 타입 한정

자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정하는 것이다.

재귀적 타입 한정은 주로 타입의 자연적 순서를 정하는 Comparable 인터페이스와 함께 쓰인다.

다음은 컬렉션에서 최댓값을 반환하는 메서드다.

public static <E extends Comparable<E>> E max(Collection<E> c) {
    if (c.isEmpty())
        throw new IllegalArgumentException("컬렉션이 비어 있습니다.");

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

    return result;
}

타입 한정인 <E extends Comparable<E>>는 "모든 타입 E는 자신과 비교할 수 있다"라고 읽을 수 있다.
즉, 상호 비교 가능하다는 뜻을 아주 정확하게 표현한 것이다.

재귀적 타입 한정은 훨씬 복잡해질 가능성이 있긴 하지만, 다행히 그런 일은 잘 일어나지 않는다.

이번 아이템에서 설명한 관용구, 여기에 와일드카드를 사용한 변형(아이템 31), 그리고 시뮬레이트한 셀프 타입 관용구(아이템 2)를 이해하고 나면 실전에서 마주치는 대부분의 재귀적 타입 한정을 무리 없이 다룰 수 있을 것이다.



📌 핵심정리

  • 제네릭 타입과 마찬가지로, 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메서드보다 제네릭 메서드가 더 안전하며 사용하기도 쉽다.
  • 타입과 마찬가지로, 메서드도 형변환 없이 사용할 수 있는 편이 좋으며, 많은 경우 그렇게 하려면 제네릭 메서드가 되어야 한다.
  • 역시 타입과 마찬가지로, 형변환을 해줘야 하는 기존 메서드는 제네릭하게 만들자. 기존 클라이언트는 그대로 둔 채 새로운 사용자의 삶을 훨씬 편하게 만들어줄 것이다. (아이템 26)
profile
백엔드 개발자

0개의 댓글