Generic Wildcards in Java β <code>?</code>, <code>? extends</code>, <code>? super</code>
A wildcard (?) stands for "some unknown type" in a generic parameter. It exists because generics are invariant by default: List<Integer> is not a subtype of List<Number>. Wildcards let you write methods that accept a family of parameterised types.
Unbounded ?
public static void printAll(List<?> list) {
for (Object o : list) System.out.println(o);
}
printAll(List.of(1, 2, 3));
printAll(List.of("a", "b"));
You can read Object from a List<?>, but you can't add anything (except null) β the compiler doesn't know what type is allowed.
Upper-bounded β ? extends T
public static double sum(List<? extends Number> nums) {
double total = 0;
for (Number n : nums) total += n.doubleValue();
return total;
}
sum(List.<Integer>of(1, 2, 3));
sum(List.<Double>of(1.0, 2.0));
You can read as Number. You can't add β the list might be a List<Integer> and accept no Doubles.
Lower-bounded β ? super T
public static void addIntegers(List<? super Integer> dst) {
dst.add(1);
dst.add(2);
}
addIntegers(new ArrayList<Number>());
addIntegers(new ArrayList<Object>());
You can add Integer (or its subtypes). You can only read as Object.
PECS β Producer Extends, Consumer Super
The mnemonic for when to use which:
- If the parameter produces values (you read from it), use
? extends T. - If the parameter consumes values (you write to it), use
? super T. - If you do both, use
T.
public static <T> void copy(List<? extends T> src, List<? super T> dst) {
for (T t : src) dst.add(t);
}
Common mistakes
- Writing
List<Object>when you meanList<?>β the first doesn't acceptList<String>, the second does. - Trying to add to
? extendsβ the compiler refuses; you don't know the exact type. - Over-using wildcards β for a single type parameter,
<T>on the method is often cleaner than? extends T.
Related
Pillar: Java generics. See also bounded types, erasure.