Matheion

MA-JAVA0 · Module 18

Wildcards: extends, super, and PECS

Topics: ? extends · ? super · PECS · Read vs write

Overview

Session 18 — Wildcards: extends, super, and PECS

Sometimes a method should accept any list whose elements are at least Number, or any list that can hold at least Integer. Wildcards—? extends T and ? super T—express that flexibility without forcing callers to pick a single concrete type argument. This session teaches variance: what you may read versus write, and the PECS rule (Producer Extends, Consumer Super).

Time: about 90 minutes.

Concepts

1. The problem wildcards solve

Suppose you write:

public static void printAll(List<Object> items) { /* ... */ }

Callers cannot pass List<String>—not a subtype of List<Object> in Java (invariance). Wildcards loosen the type while keeping operations safe.


2. ? extends T — upper bounded wildcard

List<? extends Number> reads as “a list of some unknown type that is a subtype of Number.” You may read Number (or Object) from elements, but you must not add arbitrary numbers—the compiler cannot prove the list is actually List<Integer> vs List<Double>.

public static double sumNumbers(List<? extends Number> nums) {
    double total = 0.0;
    for (Number n : nums) {
        total += n.doubleValue();
    }
    return total;
}

Here the list is a producer of numbers—you consume numbers from it.


3. ? super T — lower bounded wildcard

List<? super Integer> means “list whose element type is some supertype of Integer,” e.g. List<Number> or List<Object>. You may safely add an Integer, but reading yields only Object unless you narrow carefully—great for sink APIs.

public static void fillInts(List<? super Integer> sink) {
    sink.add(1);
    sink.add(2);
}

The list is a consumer of integers you produce.


4. PECS

Producer Extends, Consumer Super—coined by Joshua Bloch:

  • If your method reads T elements from a collection parameter, use ? extends T.
  • If your method writes T elements into a collection parameter, use ? super T.
  • If you both read and write the same T, prefer a named type parameter <T> on the method instead of a wildcard.

5. Collections.copy mental model

Collections.copy(List<? super T> dest, List<? extends T> src) pairs a consumer destination with a producer source sharing a hidden T.


6. Unbounded ?

List<?> — “list of unknown element type.” You can read elements as Object; you cannot add anything except literal null—rarely what you want except for “I truly only call size()/clear().”


7. Pitfalls

  • Trying to add into List<? extends Number>—compiler blocks it (except null).
  • Returning ? extends from APIs without documenting what callers can do—sometimes a named type parameter reads clearer.
  • Wildcards inside nested generics (Map<String, ? extends List<Integer>>)—draw the tree on paper before coding.

Examples

Example A — sum with producer wildcard

import java.util.List;

public class Totals {
    public static double sumDoubles(List<? extends Number> nums) {
        double s = 0.0;
        for (Number n : nums) {
            s += n.doubleValue();
        }
        return s;
    }
}

Both List<Integer> and List<Double> call sites compile—covariance on read.


Example B — copy integers into a wider sink

import java.util.ArrayList;
import java.util.List;

public class Buffers {
    public static void appendDefaults(List<? super Integer> sink) {
        sink.add(0);
        sink.add(-1);
    }

    public static void demo() {
        List<Number> wide = new ArrayList<>();
        appendDefaults(wide); // OK: Number is super of Integer
    }
}

If the parameter were List<Integer> only, you could not pass List<Number>—wildcard super fixes that for writes.

Practice check — wildcards and PECS

Multiple-choice check from the Matheion app lesson. Pick an answer for each question, then submit.

  1. 1.`List<? extends Number>` is best used when you…

  2. 2.`List<? super Integer>` is best used when you…

  3. 3.PECS stands for…

  4. 4.Why can't you usually `add(new Integer(1))` into `List<? extends Number>`?

  5. 5.Reading from `List<? super Integer>` with `get` yields…