Generics and wildcards

Collections · lesson 19 of 42 · 4 min read

Read ? extends and ? super without guessing, using one rule you can say out loud.

Open this lesson in the learning hub

Key points

  • A type parameter makes a collection checked at compile time: a List<String> can never hold an Integer.
  • List<? extends Number> produces numbers. You may read them; you may not add anything to it.
  • List<? super Integer> consumes integers. You may add them; whatever you read back is an Object.
  • PECS: Producer Extends, Consumer Super. Wildcards belong on parameters, rarely on return types.
  • List<?> means some unknown element type. Size and iteration still work; adding does not.
  • Generics are erased at runtime, so two differently typed lists are the same class once compiled.

Example

import java.util.*;

public class Main {

    // Produces values for us to read, so: ? extends
    static double sum(List<? extends Number> nums) {
        double total = 0;
        for (Number n : nums) total += n.doubleValue();
        return total;
    }

    // Consumes values we hand it, so: ? super
    static void fillWithInts(List<? super Integer> sink) {
        for (int i = 1; i <= 3; i++) sink.add(i);
    }

    public static void main(String[] args) {
        List<Integer> ints = List.of(1, 2, 3);
        List<Double> doubles = List.of(1.5, 2.5);
        System.out.println("sum(List<Integer>) : " + sum(ints));
        System.out.println("sum(List<Double>)  : " + sum(doubles));

        List<Number> numbers = new ArrayList<>();
        fillWithInts(numbers);
        List<Object> objects = new ArrayList<>();
        fillWithInts(objects);
        System.out.println("filled List<Number>: " + numbers);
        System.out.println("filled List<Object>: " + objects);

        List<?> unknown = ints;
        System.out.println("List<?> size       : " + unknown.size() + "   (readable, nothing can be added)");

        System.out.println("erasure at runtime : " +
                (new ArrayList<String>().getClass() == new ArrayList<Integer>().getClass()));
        System.out.println("PECS               : producer extends, consumer super");
    }
}

Producer extends, consumer super — say it once and wildcards stop being a puzzle.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.