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