Item 27. 가능하면 제네릭 함수로 만들것

static 유틸리티 함수는 제네릭화하기 좋은 후보다. Collections에 구현된 모든 “알고리즘” 함수(binarySearch나 sort같은)는 제네릭으로 구현되어 있다.

1. 일반 적인 사용

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

public static void main(String[] args){
    Set<String> guys = new HashSet<String>(Arrays.asList("Tom", "Dick", "Harry"));
    Set<String> stooges = new HashSet<String>(Arrays.asList("Larry", "Moe", "Curly"));
    
    Set<String> aflCio = union(guys, stooges);
    
    System.out.println( aflCio );
}

2. 제네릭 정적 팩토리 함수

Map<String, List<String>> m = new HashMap<String, List<String>>();

// 위와 같은 번거러움을 피하기 위해서 아래와 같은 제네릭 정적 함수 정리하여 사용(guava lib 사용)
public class Maps{
    public static <K,V> Hashmap<K,V> newHashMap(){
        return new HashMap<K,V>();
    }
}

//use
public static void main(String[] args){
    Map<String, List<String>> m = Maps.newHashMap();
    ...
}

3. 제네릭 싱글톤 팩토리 패턴

public interface UnaryFunction<T>{
    T apply(T arg);
}

// 위와 같은 항등 함수(identity function)를 구현했다고 가정함
// 항등 함수는 무상태 함수이므로 필요할 때 새 함수를 만드는 것은 낭비이므로 싱글톤으로 객체 생성하여, 
// 재사용하도록 아래와 같이 구현
public static final UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
    public Object apply(Object arg){ return arg; }
};

// IDENTITY_FUNCTION은 무상태 객체고 형인자는비한정 인자이므로(unbounded)
// 모든 자료형이 같은 객체를 공유해도 안전함.
@SuppressWarnings("unchecked")@
public static <T> UnaryFunction<T> identityFunction(){
    return (UnaryFunction<T>) IDENTITY_FUNCTION;
}

//use
public static void main(String[] args){
    String[] strings = {"jute", "hemp", "nylon"};
    UnaryFunction<String> sameString = identityFunction();
    for(String s : strings)
        System.out.println(sameString.apply(s));
}

4. 재귀적 자료형 한정(recursive type bound)

public static <T extends Comparable<T>> T max(List<T> list){
    Iterator<T> i = list.iterator();
    T result = i.next();
    while( i.hasNext() ){
        T t = i.next();
        if(0 < t.compareTo(result)){
            result = t;
        }
    }
    return result;
}

결론

  • 제네릭 자료형과 마찬가지로 제네릭 함수는 클라이언트가 직접 이력 값과 반환값의 자료형을 형변환해야 하는 함수보다 사용하기 쉽고 형 안정성도 높다.
  • 시간 날때 기존 함수를 제네릭 함수로 확장해 놓으면, 기존 클라이언트 코드를 깨지 않고도 새 사용자에게 더 좋은 API를 제공할수 있다.