6

Here is the code:

class Foo<T> {
  private final T[] array;
  @SafeVarargs
  Foo(T... items) {
    this.array = items;
  }
}

I'm getting:

[WARNING] Varargs method could cause heap pollution 
from non-reifiable varargs parameter items

What's wrong with my assignment? How to fix that? @SuppressWarnings is not an option, since I want this constructor to be truly "safe."

$ javac -version
javac 1.8.0_40
yegor256
  • 102,010
  • 123
  • 446
  • 597
  • Use a `List` instead; invoke with `new Foo(Arrays.asList(...))`. – Andy Turner Jun 21 '17 at 12:02
  • 1
    Not getting any warnings with javac or Netbeans or intellij. Using eclipse? – assylias Jun 21 '17 at 12:02
  • @assylias I compile with `-Xlint` – yegor256 Jun 21 '17 at 12:06
  • I don't see that warning with Eclipse (Neon) either. Which version of javac is this? – GhostCat Jun 21 '17 at 12:07
  • @assylias this is how it works: `javac -Werror -Xlint -Xlint:-varargs Main.java` – yegor256 Jun 21 '17 at 12:08
  • @yegor256 Mmm - actually I was compiling with maven and getting no warning (or with Netbeans and Intellij) but I do get the warning with javac if I compile the file alone. Not sure why - ignore my previous comments. – assylias Jun 21 '17 at 12:12
  • 1
    Possible duplicate of [java warning: Varargs method could cause heap pollution from non-reifiable varargs parameter](https://stackoverflow.com/questions/28914088/java-warning-varargs-method-could-cause-heap-pollution-from-non-reifiable-varar) – Oleg Estekhin Jun 21 '17 at 12:30
  • https://docs.oracle.com/javase/8/docs/technotes/guides/language/non-reifiable-varargs.html#suppressing, besides documenting the behavior, provides an example with three differently annotated calls to a vararg method. – Oleg Estekhin Jun 21 '17 at 12:32
  • 1
    @yegor256 I launched your code and I didn't saw any warning during compilation my javac -version: `javac 1.8.0_131` –  Jun 21 '17 at 12:37
  • @rukavitsya have you run it with `Xlint`? – assylias Jun 21 '17 at 12:40
  • @assylias with `-Xlint` I got this warning message, but the spec says that - `-Xlint` `"enable all recommended warnings"` and this option can simply overcome `SafeVarargs` annotation. –  Jun 21 '17 at 12:46
  • @rukavitsya No -Xlint won't show any warnings if you use the appropriate annotations. – assylias Jun 21 '17 at 12:48
  • @assylias but it's a fact that I have the warning with `-Xlint` and don't have it without this option. –  Jun 21 '17 at 12:51
  • 1
    @rukavitsya Where does it say that `Xlint` "overcomes" `SafeVarag`? Did you just guess and try to push it as fact? – Vince Jun 21 '17 at 12:55
  • @Vince Emigh No, it's just a guess, as result of running javac with and without `Xlint` option on my machine. –  Jun 21 '17 at 12:57
  • @rukavitsya Yes that's the point: -Xlint shows the warnings - and if you think one of the warnings is not relevant, you can remove it with an annotation, like `@SafeVarargs`. And the question here is: why doesn't the annotation remove the warning. – assylias Jun 21 '17 at 12:59
  • @yegor256 I checked this issue on latest version of jdk `1.8.0_131` and compile test class that creates instance of Foo uses this command `javac -Xlint:all -cp //classpath// TestFoo.java` and get no warnings. – fxrbfg Jun 21 '17 at 12:59

3 Answers3

2

From the docs:

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.

The first statement tells us @SafeVarargs suppresses unchecked warnings about:

  • non-reifiable type for your varargs
  • parameterized array creations when you call the method

In your case, @SafeVarargs is suppressing the warning on T... items. Your warning is occuring on this.array = items;.


From the JLS §9.6.4.7:

The annotation @SafeVarargs has non-local effects because it suppresses unchecked warnings at method invocation expressions in addition to an unchecked warning pertaining to the declaration of the variable arity method itself.


In contrast, the annotation @SuppressWarnings("unchecked") has local effects because it only suppresses unchecked warnings pertaining to the declaration of a method.

Vince
  • 14,470
  • 7
  • 39
  • 84
  • I think that last two quotes don't related to *"Your warning is occuring on `this.array = items;`"*. You didn't explain why `varargs` warning is thrown when we refer the varargs parameter inside the method even though there is `@SafeVarargs`. – rosshjb Dec 15 '21 at 15:21
1

Joshua Bloch explains this in Effective Java (25s chapter):

The prohibition on generic array creation can be annoying. It means, for example, that it’s not generally possible for a generic type to return an array of its element type (but see Item 29 for a partial solution). It also means that you can get confusing warnings when using varargs methods (Item 42) in combination with generic types. This is because every time you invoke a varargs method, an array is created to hold the varargs parameters. If the element type of this array is not reifiable, you get a warning. There is little you can do about these warnings other than to suppress them (Item 24), and to avoid mixing generics and varargs in your APIs.

The reason for this message is described in spec, in this part of spec, there is similar example (with class ArrayBuilder and different combinations of annotation usage)

Like alternative, try to use mix of SafeVarargs and SuppressWarnings annotations

@SafeVarargs
@SuppressWarnings( "varargs" )

HTH

  • 7
    You are explaining the **warning**. You are **not at all** answering the question why the **annotation** does not **suppress** the warning. But maybe I am wrong, and some of the upvoters can explain why they think this answer **answers** the question. – GhostCat Jun 21 '17 at 12:17
  • `@SuppressWarnings` is not an option, since all other calls of this ctor will still produce the same warning. – yegor256 Jun 21 '17 at 12:23
0

My problem was that I was using -Xlint command line javac parameter. I found out that I have to compile it with the following params:

javac -Werror -Xlint -Xlint:-varargs

That's it.

yegor256
  • 102,010
  • 123
  • 446
  • 597