In this code,
package com.example;
interface CollectorIF<T> {
// @SafeVarargs // Error: @SafeVarargs annotation cannot be applied to non-final instance method addAll
void addAll(T... values);
}
class Collector<T> implements CollectorIF<T> {
@SafeVarargs
public final void addAll(T... values) {
}
}
class Component<T> {
public void compute(T value) {
Collector<T> col1 = new Collector<>();
col1.addAll(value); // No warning
CollectorIF<T> col2 = new Collector<>();
col2.addAll(value); // Type safety: A generic array of T is created for a varargs parameter
}
}
the Type safety: A generic array of T is created for a varargs parameter
warning does not occur when using a Collector<T>
reference, due to the @SafeVarargs
annotation.
However, the warning does occur when accessing the method through the CollectorIF<T>
interface. On interface methods, @SafeVarargs
is not valid (which is obvious since the compiler can not perform any checks on the usage of the parameter in the method body).
How can the warning be avoided when accessing the method through an interface?
It is an annotation which applies on a method or constructor that takes varargs parameters. It is used to ensure that the method does not perform unsafe operations on its varargs parameters. It was included in Java7 and can only be applied on. Final methods.
Annotation Type SafeVarargsA programmer assertion that the body of the annotated method or constructor does not perform potentially unsafe operations on its varargs parameter.
There's no way to avoid this warning, because there's no way to safely define an interface that has a generic varargs method.
Another implementation of CollectiorIF
could misuse the parameter, rendering any caller of CollectorIF.addAll()
vulnerable to strange runtime behavior. You could make a case that interfaces and non-final methods should allow @SafeVarargs
(and require that implementing/overriding methods be similarly annotated), but presently the Java devs made a conscious decision not to support that pattern.
The JLS provides a little more background:
The annotation is not usable where method overriding occurs. Annotation inheritance only works on classes (not methods, interfaces, or constructors), so an @SafeVarargs-style annotation cannot be passed through instance methods in classes or through interfaces.
~JLS §9.6.4.7
In the meantime you have two choices; ignore the warning or refactor your API.
Refactoring your API is actually likely to be exactly what you want, since generic vararg methods should only be used as bridges to the real, properly-generic implementation. Instead of defining it as part of your interface (and therefore requiring all implementations implement it) provide it as a static utility method, thereby making the interface's API smaller while still giving callers the flexibility to use varargs. As of Java 8 the utility method can even be defined in the interface.
@SafeVarargs
public static <T> void addAll(CollectorIF<T> collector, T... values) {
collector.addAll(Arrays.asList(values));
}
Your interface should then define a addAll(Iterable<T> values)
method which lets implementors avoid the crufty world of generic varargs entirely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With