代码改变世界

Effective Java 28 Use bounded wildcards to increase API flexibility

2014-03-22 22:06  小郝(Kaibo Hao)  阅读(607)  评论(0编辑  收藏  举报

Get and Put Principle

PECS stands for producer-extends(? extends T), consumer-super(? super T).

  1. For maximum flexibility, use wildcard types on input parameters that represent producers or consumers.

   

// Wildcard type for parameter that serves as an E producer

public void pushAll(Iterable<? extends E> src) {

for (E e : src)

push(e);

}

   

// Wildcard type for parameter that serves as an E consumer

public void popAll(Collection<? super E> dst) {

while (!isEmpty())

dst.add(pop());

}

   

Although lists can both consume and produce values, the reduce method uses its list parameter only as an E producer, so its declaration should use a wildcard type that extends E. The parameter f represents a function that both consumes and produces E instances, so a wildcard type would be inappropriate for it. Here's the resulting method declaration:

   

// Wildcard type for parameter that serves as an E producer

static <E> E reduce(List<? extends E>list, Function<E> f, E initVal)

   

2. Do not use wildcard types as return types.

 

public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)

   

3. If the user of a class has to think about wildcard types, there is probably something wrong with the class's API.

4. Use explicit parameter for the generic method.

Set<Integer> integers = ... ;

Set<Double> doubles = ... ;

Set<Number> numbers = union(integers, doubles);

Set<Number> numbers = Union.<Number>union(integers, doubles);

   

Always use Comparable<? super T> in preference to Comparable<T>.The same is true of comparators, so you should always use Comparator<? super T> in preference to Comparator<T>.

public static <T extends Comparable<? super T>> T max(List<? extends T> list)

   

5. If a type parameter appears only once in a method declaration, replace it with a wildcard for its simplify.

// 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);

// Use this one instead of first one. But this one will not compile since the one above cannot set an element

// to the list object whose type is List<?> unless the object is null.

// And you should provide clean API list the code below.

   

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)));

}

   

Summary

Using wildcard types in your APIs, while tricky, makes the APIs far more flexible. If you write a library that will be widely used, the proper use of wildcard types should be considered mandatory. Remember the basic rule: producer-extends, consumer-super(PECS). And remember that all comparables and comparators are consumers.