Java Heap Pollution
Heap pollution means a variable points to an object of the wrong type. It happens when generic type checks are bypassed, often through a raw type.
A raw view lets an Integer into a String list
The raw List accepts the Integer with only a warning. The size and the stored value print.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
List raw = words;
raw.add(Integer.valueOf(42));
System.out.println(words.size());
System.out.println(raw.get(0));
}
}The read pays for the mistake
The polluted list is read back as a String. The cast inside the read fails at runtime.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
List raw = words;
raw.add(Integer.valueOf(42));
String first = words.get(0);
System.out.println(first);
}
}@SafeVarargs states the clean promise
The method only reads its varargs array and copies each value. The annotation states that promise in code.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> words = bundle("red", "green", "blue");
System.out.println(words);
System.out.println(words.size());
}
@SafeVarargs
static <T> List<T> bundle(T... items) {
List<T> result = new ArrayList<>();
for (T item : items) {
result.add(item);
}
return result;
}
}Example
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> words = bundle("one", "two");
List<Integer> numbers = bundle(Integer.valueOf(10), Integer.valueOf(20));
System.out.println(words);
System.out.println(numbers);
}
@SafeVarargs
static <T> List<T> bundle(T... items) {
List<T> result = new ArrayList<>();
for (T item : items) {
result.add(item);
}
return result;
}
}Key points
- A raw type is a generic type used without its type argument.
- A raw view of a List<String> accepts any object, and the compiler only warns.
- The failure lands at the read, far from the line that caused it.
- A reifiable type keeps its element type at runtime, like an array does.
- Generic types are not reifiable, and their element type is erased.
- @SafeVarargs states that a generic varargs method uses its array safely.
In this example, one generic varargs method builds a String list and an Integer list, and each list holds only values of its own type.
Note
Unchecked warnings mark the spots where pollution can enter.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What is heap pollution?