6

I've finally got around to trying to get rid of all those new compiler warnings that Java 7 has kindly generated. I these two left that I cannot fathom. Is there any way of getting rid of them without suppressing them?

Constructing an array of generically typed objects (where can I put a in the array creation?):

  static final int N = 10;
//warning: [unchecked] unchecked conversion
  static final Set<Widget>[] queued = new ConcurrentSkipListSet[N];
//required: Set<Widget>[]
//found:    ConcurrentSkipListSet[]

Generic varargs (Seems to happen almost everywhere I accept varargs of a generic type):

class Foo<T> {
//warning: [unchecked] Possible heap pollution from parameterized vararg type T
  public void add(T... entries) {
//where T is a type-variable:
//T extends Object declared in class Foo

BTW: I already have:

  // Add many entries to the list.
  public void add(List<T> entries) {
    // ...
  }

  // Add a number of entries.
  public void add(T... entries) {
    // Make a list of them.
    add(Arrays.<T>asList(entries));
  }
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213

4 Answers4

7

For the first one:

static final Set<Widget>[] queued = new ConcurrentSkipListSet<>[N];

Prior to Java 7, it would have to be:

static final Set<Widget>[] queued = new ConcurrentSkipListSet<Widget>[N];

However, you are probably better off declaring this as an ArrayList<Set<Widget>>. Generally, mixing arrays and generics is a bit difficult in Java.

static final List<Set<Widget>> queued = new ArrayList<>();
// or new ArrayList<Set<Widget>>();

Regarding the second, see this thread. Although you can suppress the message, it's actually warning about a real danger. The bottom line of that thread is that the safe thing to do is to change your method signature (and the corresponding calls) to:

class Foo<T> {
    public void add(List<T> entries) {
        . . .

The issue is basically the same as the first: you should not be creating arrays of generics.

Community
  • 1
  • 1
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • I have tried both of these - I get `error: generic array creation` in both cases. – OldCurmudgeon Mar 21 '13 at 16:07
  • @OldCurmudgeon - I modified my answer a bit. Use `ArrayList>`. – Ted Hopp Mar 21 '13 at 16:08
  • Your reference ultimately points to an Oracle page discussing the problem but I do not see a solution there. – OldCurmudgeon Mar 21 '13 at 16:10
  • @OldCurmudgeon - I don't know that there is a good solution. It's basically the same problem as the first: you should not create an array of generics. You can possibly turn off enough warnings to get rid of the message, but the warning is there for a reason. The constructive suggestion is to change your method signature to take a `List` instead of `T...`. – Ted Hopp Mar 21 '13 at 16:14
  • I've done the `List>` change (grudgingly because it hides the fact that there are exactly `N` of them) but I don't see how I can replace `public void add(T... entries)` with `public void add(List entries)`. See additions in the question. – OldCurmudgeon Mar 21 '13 at 16:24
  • @OldCurmudgeon - Regarding the first point, you can pass the capacity to the `ArrayList` constructor; in that case there will be no wasted space allocated in the internal array. Regarding the second point, what you're doing is perfectly safe, so go ahead and suppress the message using one of [the methods described suggested by Oracle](http://docs.oracle.com/javase/7/docs/technotes/guides/language/non-reifiable-varargs.html#suppressing). – Ted Hopp Mar 21 '13 at 17:25
2

To resolve the second, you need to add @SafeVarargs to the method declaration.

From the javadocs, this is:

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.

dogbane
  • 266,786
  • 75
  • 396
  • 414
1

Generic array creation:

static final ConcurrentSkipListSet<Widget>[] queued = newArray(N);
// note: declare the most specific type for private objects


@SafeVarargs
static <E> E[] newArray(int length, E... array)
{
    return Arrays.copyOf(array, length);
}

How does it work - since newArray is an vararg method, an E[] array argument must be passed in, therefore the method body has access to the type of E[]. This is theoretically correct, and if there's no erasure, it'll be totally type safe at runtime. With erasure, we only have erased type of E[] at runtime, that's fine, we return the same erased type too.

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • Wow!! Solved both my problems in one hit. I don't understand how `newArray(N)` actually passes an array of the correct type to `newArray` but hats off to you sir. BTW - I adjusted it to `static final ConcurrentSkipListSet[] queued = DoubleBufferedList.>newArray(N);` for my tests. – OldCurmudgeon Mar 22 '13 at 10:27
  • why not simply `static final ConcurrentSkipListSet[] queued = DoubleBufferedList.newArray(N);` – ZhongYu Mar 22 '13 at 11:13
  • Because when I traced into it that form gave me an `Object[]` in the 2nd parameter. With mine I got a `ConcurrentSkipListSet[]` which feels better for me. I realise it is a very minor difference because they are both fundamentally `Object[]`. – OldCurmudgeon Mar 22 '13 at 11:43
  • BTW - Have you any references to documentation on this new seemingly magical creation of un-passed parameters? – OldCurmudgeon Mar 22 '13 at 11:47
  • It shouldn't create an `Object[]`. looks like a compiler bug, I'll ask the compiler-dev list - http://mail.openjdk.java.net/pipermail/compiler-dev/2013-March/005896.html – ZhongYu Mar 22 '13 at 15:47
  • 1
    It's confirmed to be a compiler bug that's fixed in java8. – ZhongYu Mar 22 '13 at 20:07