Saturday, July 30, 2011

Java 7: Safe Varargs Method Invocation

In previous versions of Java, when you invoke a varargs method with a non-reifiable varargs type, the compiler generates a warning on the calling statement. Consider the code:
//varargs method
public static <T> void print(T... a) {
  for (T t : a) {
      System.out.println(t);
  }
}

//calling method
public static void main(String[] args){

  print("Hello", "World"); //this is fine

  print(new Pair<Integer,String>(1,"One"), new Pair<Integer,String>(2,"Two"));
  //WARNING: Type safety : A generic array of Pair<Integer,String>
  //is created for a varargs parameter
}
This because the compiler tries to create an array of Pair<Integer,String>[] to hold the varargs, which is not permitted because Pair<Integer,String> is type erased at runtime to just Pair. (More information here.) To suppress this warning, you need to add @SuppressWarnings("unchecked") to each method which makes a call to the varargs method.

In JDK7, the warning has been moved from the call site to the varargs method declaration and you can annotate the varargs method with @SafeVarargs in order to suppress it. This reduces the total number of warnings reported and those that have to be suppressed.

@SafeVarargs
// WARNING SUPPRESSED: Type safety: Potential heap pollution via varargs parameter a
public static <T> void print(T... a) {
  for (T t : a) {
      System.out.println(t);
  }
}

public static void main(String[] args){
  print("Hello", "World");
  print(new Pair<Integer,String>(1,"One"), new Pair<Integer,String>(2,"Two"));
  //no warnings :)
}
You can see this annotation used in JDK7's Arrays.asList method:

@SafeVarargs
public static <T> List<T> asList(T... a) {
   return new ArrayList<>(a);
}
Eclipse support:
Quick fix gives you the option to Add @SafeVarargs to your method.

Further Reading:
Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods

1 comment: