Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Warning for generic varargs

I have declared the following method:

private void mockInvokeDBHandler(Map<String, Object>... rows) {
    List<Map<String, Object>> allRows = Arrays.asList(rows));
    // rest of method omitted
}

It is invoked by clients using something like

Map<String, Object> row1 = new HashMap<String, Object>();
Map<String, Object> row2 = new HashMap<String, Object>();

mockInvokeDBHandler(row1, row2);

However, the last line shown above generates a warning

Type safety : A generic array of Map is created for a varargs parameter

I don't fully understand this, but I guess it's because varargs params are converted to arrays, and it's a bad idea to have an array whose type is a generic class (because generics are invariant, whereas arrays aren't).

I could resolve this problem by redifining the method as

private void mockInvokeDBHandler(List<Map<String, Object>> rows) {
}

But this places the burden of putting the row objects into a List on the client, which I'd rather avoid. Is there a better solution?

like image 229
Dónal Avatar asked Nov 23 '10 15:11

Dónal


3 Answers

To pass the arguments to a varargs method the compiler will place the arguments into an array.

The warning is to let you know that the compiler cannot guarantee that each of the elements in the array - each of the arguments to the varags method - is truly a Map<String, Object>.

This is a bit of an annoying warning because there is no way you can work around this, other than to redefine the method signature to not use varargs. IMO it is safe to ignore as long as you are pretty sure of the actual run-time types of these arguments (which in this case, you are).

like image 155
matt b Avatar answered Nov 15 '22 15:11

matt b


There's no way to avoid this warning, other than adding @SuppresWarning("unchecked") to the method :)

Since you say it's a private method there's no "clients" in this case and you're in control of the method, so ignoring the warning seems reasonable.

A few times when I've created methods taking parameterized types as a varargs parameter, I've created some overloads:

void mockInvokeDBHandler(Map<String, Object> map1)
void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2)
void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2, Map<String, Object>... othermaps)

That could avoid some of the warnings, depending on how many arguments are supplied.

like image 36
Uhlen Avatar answered Nov 15 '22 15:11

Uhlen


For anyone landing here, the answers are a little old. Java 7 introduced the @Safevarargs annotation to address this:

@SafeVarargs
private void mockInvokeDBHandler(Map<String, Object>... rows) {

From the javadoc:

A programmer assertion that the body of the annotated method or constructor does not perform potentially unsafe operations on its varargs parameter. Applying this annotation to a method or constructor suppresses unchecked warnings about a non-reifiable variable arity (vararg) type and suppresses unchecked warnings about parameterized array creation at call sites.

like image 31
Brendan Humphreys Avatar answered Nov 15 '22 14:11

Brendan Humphreys