Java Wildcards
In this page:
List<?> list // unknown type
List<? extends UpperBound> list // read-only producer
List<? super LowerBound> list // consumer
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?
// Import java.util.List so it can be used by its short name
import java.util.List;
// Define the class Main
public class Main {
static void printSize(List<?> list) {
// Print a line to the console
System.out.println("Size: " + list.size());
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
printSize(List.of("a", "b", "c"));
printSize(List.of(1, 2));
}
}
Login to try C/C++/Java/PHP code in the editor
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
// Import java.util.List so it can be used by its short name
import java.util.List;
// Define the class Main
public class Main {
static void printAll(List<?> list) {
// Print a line to the console
System.out.println("Items: " + list.size());
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
printAll(List.of(1, 2, 3));
}
}
Login to try C/C++/Java/PHP code in the editor
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
// Import java.util.List so it can be used by its short name
import java.util.List;
// Define the class Main
public class Main {
static double sum(List<? extends Number> nums) {
// Declare total and set it to 0
double total = 0;
for (Number n : nums) total += n.doubleValue();
// Send total back to the caller
return total;
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Print a line to the console
System.out.println(sum(List.of(1, 2, 3)));
}
}
Login to try C/C++/Java/PHP code in the editor
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
// Import java.util.List so it can be used by its short name
import java.util.List;
// Import java.util.ArrayList so it can be used by its short name
import java.util.ArrayList;
// Define the class Main
public class Main {
static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a new ArrayList object and store it in numbers
List<Number> numbers = new ArrayList<>();
addNumbers(numbers);
// Print a line to the console
System.out.println(numbers);
}
}
Login to try C/C++/Java/PHP code in the editor
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)
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)));
}
}
Login to try C/C++/Java/PHP code in the editor
- Trying to call
list.add(5)on aList<?>orList<? extends Number>, which does not compile because the compiler cannot know the exact element type (onlynullcan be added). - Mixing up
extendsandsuper: use? extends Tto read from a collection and? super Tto write into it (PECS). - Thinking
List<?>andList<Object>are the same, when aList<String>can be passed toList<?>but not toList<Object>.
- Generics let classes and methods work with different types while keeping type safety.
- Generic classes and generic methods are written once and reused for many types.
- Wildcards give flexibility when a method must accept several related generic types.
Chapter Quiz — Complete all 4 topics to unlock
0/4 topics done
Complete these topics first: