Java Wildcards
A wildcard is a question mark used as a type argument when the exact element type is unknown or flexible. Wildcards let one method accept lists of related types.
Reading an unknown list
show accepts a list of any element type. It reads the size and the first element as an Object.
import java.util.ArrayList;
import java.util.List;
public class Main {
static void show(List<?> list) {
System.out.println(list.size());
Object first = list.get(0);
System.out.println(first);
}
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("Ana");
names.add("Ben");
show(names);
ArrayList<Integer> scores = new ArrayList<>();
scores.add(90);
show(scores);
}
}A producer of numbers
total reads each element as a Number and adds its doubleValue. Integer and Double lists both fit the extends bound.
import java.util.ArrayList;
import java.util.List;
public class Main {
static double total(List<? extends Number> numbers) {
double sum = 0;
for (Number n : numbers) {
sum += n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
ArrayList<Integer> scores = new ArrayList<>();
scores.add(10);
scores.add(20);
System.out.println(total(scores));
ArrayList<Double> prices = new ArrayList<>();
prices.add(1.5);
prices.add(2.5);
System.out.println(total(prices));
}
}A producer refuses an add
addScore tries to put an Integer into a List<? extends Number>. The list might really hold Doubles, so the compiler refuses the add.
import java.util.ArrayList;
import java.util.List;
public class Main {
static void addScore(List<? extends Number> numbers) {
numbers.add(Integer.valueOf(90));
}
public static void main(String[] args) {
ArrayList<Integer> scores = new ArrayList<>();
addScore(scores);
System.out.println(scores.size());
}
}A consumer takes integers in
fill adds two integers to any list that can hold them. The list here is a List<Number>, and its contents print afterwards.
import java.util.ArrayList;
import java.util.List;
public class Main {
static void fill(List<? super Integer> list) {
list.add(10);
list.add(20);
}
public static void main(String[] args) {
ArrayList<Number> numbers = new ArrayList<>();
fill(numbers);
System.out.println(numbers);
Object first = numbers.get(0);
System.out.println(first);
}
}Example
import java.util.ArrayList;
import java.util.List;
public class Main {
static void fill(List<? super Integer> list) {
list.add(10);
list.add(20);
}
static double total(List<? extends Number> numbers) {
double sum = 0;
for (Number n : numbers) {
sum += n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
ArrayList<Number> numbers = new ArrayList<>();
fill(numbers);
System.out.println(numbers.size());
System.out.println(total(numbers));
}
}Key points
- List<?> is a list of an unknown type, and its elements can be read as Object.
- List<? extends Number> is a producer that gives Number values out, so reads are safe.
- Nothing can be added to a producer list, because the exact element type stays unknown.
- List<? super Integer> is a consumer that takes Integer values in.
- PECS stands for Producer Extends, Consumer Super, and it sums up which bound fits each job.
In this example, the consumer method fills a list of Number with integers, and the producer method then totals the same list. The super bound fits the writing job and the extends bound fits the reading job.
Note
A value read from a consumer list comes back typed as Object.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Which declaration fits a method that only reads numbers from a list?