Codectionary / Developer documentation / Java

Generic Wildcards: extends and super

Read numeric values from producers and add integers to compatible consumers safely.

What it is and why to use it

List<Integer> is not a subtype of List<Number>, because a writable List<Number> could accept a Double. Wildcards describe the flexibility a method actually needs. ? extends Number lets it read numbers from several specific list types; ? super Integer lets it add integers to lists of Integer or a supertype.

How it works

The producer-extends, consumer-super guideline is often shortened to PECS. sum reads values as Number and calls doubleValue. addOne can insert Integer but cannot assume that values read back are Integer. This is a compile-time constraint, not a conversion of the underlying collection.

Common mistakes and limitations

An extends wildcard is not an immutable view: the API may still permit removal or clearing. You generally cannot add a non-null element through it because the precise element type is unknown. Avoid raw List types that bypass useful checks.

Try it and keep learning

Save the complete example below as Main.java. With a JDK supporting Java 17, compile using javac --release 17 Main.java, then run java Main from the same directory. These examples need only the standard library and fixed input; they do not require packages, files or network access.

Syntax

List<? extends Number> source; List<? super Integer> destination;

Examples

Generic Wildcards: extends and super

Complete Main.java example — Java 17 or later, without preview features.

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

public class Main {
  static double sum(List<? extends Number> values) {
    double total = 0;
    for (Number value : values) total += value.doubleValue();
    return total;
  }
  static void addOne(List<? super Integer> values) { values.add(1); }

  public static void main(String[] args) {
    List<Integer> scores = List.of(2, 3);
    List<Number> destination = new ArrayList<>();
    addOne(destination);
    System.out.println(sum(scores));
    System.out.println(destination);
  }
}
  1. sum accepts List<Integer> because it only needs to read each value as a Number.
  2. doubleValue converts each value for addition and the resulting double prints as 5.0.
  3. addOne accepts List<Number>, which can safely store an Integer; the destination prints [1]. The method signatures describe the direction in which data moves.
  4. Expected output: 5.0 [1]

Best practices

  • Use wildcards on parameters when they express the required flexibility.
  • Keep a precise type when the method both consumes and produces the same element type.

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading