요약

이왕이면 형변환하는 기존 메서드는 제네릭 메서드로 바꾸자. 안정성과 사용성 면에서 더 낫다.

클라이언트에서 형변환하는 메서드는 되도록이면 만들지 말자.

 

제네릭 메서드란?

타입 매개변수를 사용하는 메서드를 의미한다.

제네릭 메서드 작성 방법

메서드 선언에서의 원소 타입을 타입 매개변수(E)로 명시하고, 메서드 안에서도 이 타입 매개변수만 사용하게 하면 된다.

// [접근제어자] static [타입 매개변수 목록] [반환타입] [함수명](파라미터)
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet<>(s1);
    result.addAll(s2);
    return result;
}
  • 특징
    • 타입 매개변수 목록 : <E>
    • 반환 타입 : Set<E>
    • 파라미터 2개, 반환 객체 1개 모두 같은 타입이어야 한다.
    → 컴파일 에러 x, 타입 안전, 사용하기 쉬움

 

제네릭 싱글턴 팩터리

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

(기존 타입) → (요청한 타입 매개변수)

  • 예시 : Collections.reverseOrder, Collections.emptySet
@SuppressWarnings("unchecked")
public static <T> Comparator<T> reverseOrder() {
     return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
}

@SuppressWarnings("unchecked")
public static final <T> Set<T> emptySet() {
    return (Set<T>) EMPTY_SET;
}

 

 

예시 : 항등함수

항등함수는 입력 값을 수정 없이 그대로 반환하는 특별한 함수를 의미한다.

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

@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
    return (UnaryOperator<T>) IDENTITY_FN;
}
  • 필드 IDENTITY_FN의 타입 = UnaryOperator<Object>
  • identityFunction()의 반환 타입 = UnaryOperator<T>이다.
  • 따라서 UnaryOperator<Object> ≠ UnaryOperator<T> 이기에 비검사 형변환 경고가 발생
    • 이때 항등함수는 입력 값을 수정 없이 그대로 반환하는 함수이므로, 타입 안전하다.
    • 위에서 발생한 비검사 형변환 경고는 숨겨도 안전하기에 @SuppressWarning(”unchecked”) 설정

 

재귀적 타입 한정(recursive type bound)

자기 자신이 들어간 표현식(<E extends Comparable<E>>)을 활용해 타입 매개변수의 허용 범위를 한정하는 개념이다. 재귀적 타입 한정은 주로 타입의 자연적 순서를 정하는 Comparable 인터페이스와 함께 쓰인다.

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

new Comparable<String> -> String 타입만 사용가능
  • compareTo()의 매개변수 T는 Comparable<T>를 구현한 타입이 비교할 수 있는 원소 타입을 정의한다 → 한 타입만 사용하도록 강제시키기 때문에 타입 안정성 보장
  • String은 Comparable<String>을 구현, Integer는 Comparable<Integer>를 구현하는 식
// 파라미터 타입 Collection<E>, 타입 파라미터 목록이 <E extends Comparable<E>>이므로 
// 파라미터에 E를 포함한 자식 타입만 입력될 수 있다는 의미?
// 컬렉션에서 최댓값 반환
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;
}
  • 파라미터 타입이 Comparable 컬렉션인 경우, 컬렉션 원소의 정렬/검색/최솟값/최댓값을 구하는 것
  • Comparable<T>를 상속한 타입만 들어가게 보장할 수 있음 → 타입 안정성 보장
  • 컬렉션에 담긴 모든 원소가 상호 비교될 수 있어야함 → 컬렉션에 담긴 모든 원소가 같은 타입이어야 한다.

+ Recent posts