← Back to Advanced Java Course | Chapter 1: Generics | Lesson 4 of 4

Java Wildcards

What is a Wildcard?

In generic code, the question mark (?) is called a wildcard, and it represents an unknown type parameter rather than a fixed one. Wildcards let a single method signature accept collections of varied, related parameter types instead of locking callers into one exact type.

Example: What is a Wildcard?

java
import java.util.List;
public class Main {
	static void printSize(List<?> list) {
		System.out.println("Size: " + list.size());
	}
	public static void main(String[] args) {
		printSize(List.of("a", "b", "c"));
		printSize(List.of(1, 2));
	}
}

Unbounded Wildcards

An unbounded wildcard is written as a single question mark, like List<?>, and it represents any type parameter whatsoever. It's most useful for methods that only need to read from a collection's known Object-level API, such as printing its size, without caring what the elements actually are.

Example: Unbounded Wildcards

java
import java.util.List;
public class Main {
	static void printAll(List<?> list) {
		System.out.println("Items: " + list.size());
	}
	public static void main(String[] args) {
		printAll(List.of(1, 2, 3));
	}
}

Upper Bounded Wildcards

An upper bounded wildcard restricts the type parameter to a specific class or its subclasses, written using the extends keyword, for example <? extends Number>. This lets a method safely read values out of the collection as that upper-bound type, since every possible element is guaranteed to be at least that type.

Example: Upper Bounded Wildcards

java
import java.util.List;
public class Main {
	static double sum(List<? extends Number> nums) {
		double total = 0;
		for (Number n : nums) total += n.doubleValue();
		return total;
	}
	public static void main(String[] args) {
		System.out.println(sum(List.of(1, 2, 3)));
	}
}

Lower Bounded Wildcards

A lower bounded wildcard restricts the type parameter to a specific class or its superclasses, written using the super keyword, for example <? super Integer>. This lets a method safely write values of that type into the collection, since any superclass container is guaranteed to be able to hold them.

Example: Lower Bounded Wildcards

java
import java.util.List;
import java.util.ArrayList;
public class Main {
	static void addNumbers(List<? super Integer> list) {
		list.add(10);
		list.add(20);
	}
	public static void main(String[] args) {
		List<Number> numbers = new ArrayList<>();
		addNumbers(numbers);
		System.out.println(numbers);
	}
}

Wildcard Guidelines (PECS)

The PECS mnemonic sums up when to use each: Producer Extends, Consumer Super. Use an extends wildcard when a collection only produces values you're reading out of it, and a super wildcard when a collection only consumes values you're putting into it.

Example: Wildcard Guidelines (PECS)

java
import java.util.List;
public class Main {
	static double sum(List<? extends Number> producer) { // Producer Extends
		double total = 0;
		for (Number n : producer) total += n.doubleValue();
		return total;
	}
	static void fill(List<? super Integer> consumer) { // Consumer Super
		consumer.add(1);
	}
	public static void main(String[] args) {
		System.out.println(sum(List.of(1, 2, 3)));
	}
}
🔒

Chapter Quiz — Complete all 4 topics to unlock

0/4 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.