Item 28 - Use bounded wild cards to increase API flexibility

From Effective Java 2/e by Joshua Bloch

Parameterized type is invariant, sometimes you need more flexibility than invariant typing can provide!

public class Stack<E> {
   public Stack();
   public void push(E e);
   public E pop();
   public boolean isEmpty();
}

// pushAll method without wildcard type - deficient!
public void pushAll(Iterable<E> src) {
   for (E e : src)
      push(e);
}

// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
   for (E e : src)
      push(e);
}

// popAll method without wildcard type - deficient!
public void popAll(Collection<E> dst) {
   while (!isEmpty())
      dst.add(pop());
}

// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
   while (!isEmpty())
      dst.add(pop());
}
  • For maximum flexibility, use wildcard types on input parameters that represent producers or consumers
    • PECS stands for producer-extends, consumer-super.
  • Do not use wildcard types as return types
    • Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code
    • If the user of a class has to think about wildcard types, there is probably something wrong with the class’s API
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {...}
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {...}

Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
// error message: incompatible types
Set<Number> numbers = union(integers, doubles);
// explicit type parameter
Set<Number> numbers = Union.<Number>union(integers, doubles);
// always use Comparator<? super T> in preference to Comparator<T>
public static <T extends Comparable<T>> T max(List<T> list) {...}
public static <T extends Comparable<? super T>> T max(List<? extends T> list) {
   Iterator<? extends T> i = list.iterator();
   T result = i.next();
   while (i.hasNext()) {
      T t = i.next();
      if (t.compareTo(result) > 0)
         result = t;
   }
   return result;
}

One more wildcard-related topic

There is a duality between type parameters and wildcards, and many methods can be declared using one or the other

// Two possible declarations for the swap method
public static <E> void swap(List<E> list, int i, int j);

public static void swap(List<?> list, int i, int j) {
       swapHelper(list, i, j);
}
// Private helper method for wildcard capture
private static <E> void swapHelper(List<E> list, int i, int j) {
   list.set(i, list.set(j, list.get(i)));
}

In a public API, the second is better because it’s simpler. You pass in a list—any list—and the method swaps the indexed elements.

if a type parameter appears only once in a method declaration, replace it with a wildcard

Posted by The Finest Artist