OOP

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.

Java 21 (core language)

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