整理Effective Java書中Item 30: Favor generic methods心得筆記

主旨

本篇針對泛型方法的說明

範例

泛型方法重點在於安全性,下面透過union這個方法來說明在需要定義限制裡面的所有集合輸入及輸出參數必需相同型態。

原型方法是不被接受的寫法

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

泛型方法應該限制輸入及輸出參數必需相同型態

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

接續上面的說明帶出了Generic singleton factory泛型單例工廠模式,這裡點名了現有的Collections.reverseOrder()以及 Collections.emptySet()都是這模式。下面先用一個沒有使用泛型單例工廠的方式

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

public class NotGenericSingletonFactory {

    static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
        public Object apply(Object data) {
            return data;
        }
    };

    public static void main(String[] args) {
        String name = "Apple";
        String name2 = (String)(ID_FUNC.apply(name)); // 這裡必須 cast ><
        BigDecimal amount = new BigDecimal("12340");
        BigDecimal amount2 = (BigDecimal)(ID_FUNC.apply(amount)); // 這裡必須 cast ><

    }
}

為了這避免轉型,針對不同類型增加冗長對應程式碼

public static UnaryFunction<String> ID_FUNC_STRING = new UnaryFunction<String>() {
    public String apply(String data) {
        return data;
    }
};

public static UnaryFunction<BigDecimal> ID_FUNC_DECIMAL = new UnaryFunction<BigDecimal>() {
    public Number apply(BigDecimal data) {
        return data;
    }
};

public static UnaryFunction<Number> ID_FUNC_NUM = new UnaryFunction<Number>() {
    public Number apply(Number data) {
        return data;
    }
};

為了解決上述問題,這裡可以改成泛型單例工廠模式

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


public class GenericSingletonFactory {

    static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
        public Object apply(Object data) {
            return data;
        }
    };

    public static <T> UnaryFunction<T> idFunction()
    {
        return (UnaryFunction<T>) ID_FUNC;
    }

    public static void main(String[] args) {
        UnaryFunction<String> names = idFunction();
        String name = "Apple";
        String name2 = names.apply(name);

        UnaryFunction<BigDecimal> amounts = idFunction();
        BigDecimal amount = new BigDecimal("12340");
        BigDecimal amount2 = amounts.apply(amount);

    }
}

來看看原始碼Collections.reverseOrder(),透過泛型單例工廠完美解決

    public static <T> Comparator<T> reverseOrder() {
        return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
    }

小結

型別安全一直都是一大重點,而泛型方法需要更多實戰經驗才能更加熟悉,在要求輸入輸出型態確保不用轉型,使得程式更加清楚具有通用性以及安全性。