I have a sort of util method to transform a varargs of a type into an array of that type - it looks like this:
public K[] array(K... ks) {
return ks;
}
The use case is so that instead of defining an array when calling a method which requires an array, you can simply do array(val1, val2, val3).
However, IntelliJ gives me heap pollution warnings. I understand what this means to an extent, but I don't have much experience with the specifics - so, I would like to know whether I can add @SafeVarargs and whether this method is actually safe.
IntelliJ says:
Problem synopsis Possible heap pollution from parameterized vararg type at line 249
Problem resolution Make final and annotate as @SafeVarargs
K is declared as the type parameter of a class, along with V.
No, it's not safe - if called from another method which is using generics. Here's a complete example which looks okay, but throws an exception:
class Utility<K> {
public K[] array(K... ks) {
return ks;
}
public K[] otherMethod(K k1, K k2) {
return array(k1, k2);
}
}
class Test {
public static void main(String[] args) throws Exception {
Utility<String> util = new Utility<String>();
// Bang!
String[] array = util.otherMethod("foo", "bar");
}
}
When the compiler creates the bytecode for otherMethod
, it can't create an array of the right kind to pass into array
, because it doesn't know the type of K
. Due to type erasure, it just creates an Object[]
with the values. So in main
, there's a hidden cast from the result of otherMethod
to String[]
... and that fails at execution time.
If you call array
directly from code which really knows the types of the arguments, then it's fine, because the implicitly-created array will be of the right type.
See more on this question at Stackoverflow