Item 27 - Favor generic methods

From Effective Java 2/e by Joshua Bloch

Static utility methods are particularly good candidates for generification

All of the “algorithm” methods in Collections (such as binarySearch and sort) have been generified

The type parameter list, which declares the type parameter, goes between the method’s modifiers and its return type

// Uses raw types - unacceptable! (Item 23)
public static Set union(Set s1, Set s2) {
   Set result = new HashSet(s1);
   result.addAll(s2);
   return result;
}

// Generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
   Set<E> result = new HashSet<E>(s1); result.addAll(s2);
   return result;
}
  • Compiles without generating any warnings
  • Provides type safety as well as ease of use

Type inference

  • The compiler figures out the value of the type parameters by examining the types of the method arguments
// Type inference for generic contstructor
Map<String, List<String>> anagrams = new HashMap<>();

// Generic static factory method
public static <K, V> HashMap<K, V> newHashMap() {
   return new HashMap<K, V>();
}

// Parameterized type instance creation with static factory
Map<String, List<String>> anagrams = newHashMap();

Generic singleton pattern

// Generic singleton factory pattern
private static UnaryFunction<Object> IDENTITY_FUNCTION =
   new UnaryFunction<Object>() {
      public Object apply(Object arg) { return arg; }
   };

// IDENTITY_FUNCTION is stateless and its type parameter is
// unbounded so it's safe to share one instance across all types.
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
   return (UnaryFunction<T>) IDENTITY_FUNCTION;
}

// Sample program to exercise generic singleton
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));

   Number[] numbers = { 1, 2.0, 3L };
   UnaryFunction<Number> sameNumber = identityFunction();
   for (Number n : numbers)
      System.out.println(sameNumber.apply(n));
}

Recursive type bound

for a type parameter to be bounded by some expression involving that type parameter itself

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

// Returns the maximum value in a list - uses 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 (t.compareTo(result) > 0)
         result = t;
   }
   return result;
}

Posted by The Finest Artist