25. Bounded Wildcards (PECS)
Upper-bounded wildcards (? extends T) allow reading from a generic structure; lower-bounded (? super T) allow writing โ remembered with the PECS mnemonic: Producer Extends, Consumer Super.
Explanation
List<? extends Number> says "a List of some specific subtype of Number". You can read from it (each element is at least a Number), but you cannot add anything (the compiler doesn't know the exact subtype). This makes it a producer of values.
List<? super Integer> says "a List of some specific supertype of Integer". You can add Integer values to it (an Integer is-a Integer, and is-a Number, and is-a Object), but you can only read Object values out. This makes it a consumer.
PECS (Producer Extends, Consumer Super) is the mnemonic from Effective Java: if a generic parameter only produces values (you read from it), use extends. If it only consumes values (you write to it), use super. The wildcard ? (unbounded) means you can only read Object and cannot write at all (except null).
Example
import java.util.ArrayList;
import java.util.List;
public class BoundedWildcards {
// Producer: reads from src -> extends (PECS)
static double sumList(List<? extends Number> src) {
double total = 0;
for (Number n : src) total += n.doubleValue();
return total;
}
// Consumer: writes to dest -> super (PECS)
static void copyIntegers(List<? super Integer> dest, int count) {
for (int i = 0; i < count; i++) dest.add(i);
}
// Both: copy(src, dest) โ classic Collections.copy-style
static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (T item : src) dest.add(item);
}
public static void main(String[] args) {
List<Integer> ints = List.of(1, 2, 3);
List<Double> doubles = List.of(1.5, 2.5);
// Extends: accepts List<Integer>, List<Double>, List<Number>
System.out.println("Sum ints: " + sumList(ints)); // 6.0
System.out.println("Sum doubles: " + sumList(doubles)); // 4.0
// Super: accepts List<Integer>, List<Number>, List<Object>
List<Number> numbers = new ArrayList<>();
copyIntegers(numbers, 3);
System.out.println("Numbers: " + numbers); // [0, 1, 2]
List<Object> objects = new ArrayList<>();
copy(ints, objects); // copy List<Integer> -> List<Object>
System.out.println("Objects: " + objects); // [1, 2, 3]
}
}Sources
- https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html โ Wildcards tutorial
- https://docs.oracle.com/javase/tutorial/java/generics/moreGenerics.html โ More fun with wildcards (PECS)