What is an apparently correct example of Java code causing heap pollution?

Good question. This has bothered me quite a while too. There are two things here - you don't care about the actual runtime type of the elements within the array, like the example that you have shown:

public static <T> LinkedList<T> list(T... elements) {
    // suppose you iterate over them and add
}

This is where @SafeVarargs is well, safe.

And the second one is where you DO care about the runtime type of the elements within the array (even if so by accident). Arrays, in java, can not be generic, so you can not create a type T [] ts = new T[10], but you can declare a type T[] ts... and because arrays are covariant you can cast an Object[] to a T[] - if you know the types match.

All this becomes interesting when you pass a generic array:

// create a single element "generic" array
static <T> T[] singleElement(T elem) {
    @SuppressWarnings("unchecked")
    T[] array = (T[]) new Object[] { elem };
    return self(array);
}

// @SafeVarargs
static <T> T[] self(T... ts) {
    return ts;
}

Invoking this with Integer[] ints = singleElement(1); looks perfectly legal, but will break at runtime, this is where placing @SafeVarargs would be unsafe.

It will break because that cast (T[]) is actually useless and does not enforce any compile time checks. Even if you rewrote that method as:

 static <T> T[] singleElement(T elem) {
    @SuppressWarnings("unchecked")
    T[] array = (T[]) new Object[]{elem};
    System.out.println(array.getClass());
    return array;
}

it would still not work.


To declare generic arrays T[] in Java is problematic because their type is not known at compile time and as a consequence they can be misused, as the examples in the question show. So the Java compiler issues warnings whenever this is done.

For example, if we declare a generic array as in

T[] tArray = (T[]) new Object[] { 42 };

we get an "unchecked cast" warning.

Besides such casts, the only other way of introducing a generic array into a program is by using a generic varargs. For example, in

void bar() {
    foo(new Integer[]{ 42 })
}

void foo(T... args) {
}

Again here a generic array is being introduced, but in a different way than an unchecked cast, so it gets its own specific warning to make sure the user is not misusing it.

Indeed, as long as one is not converting the array to an array of a different type, it seems that using @SafeVarargs should be safe to use, barring atypical type conversions.