19

Possible Duplicate:
What’s the reason I can’t create generic array types in Java?

HashSet<Integer>[] rows = new HashSet<Integer>[9];

gives me a compilation error: generic array creation.

Community
  • 1
  • 1
Murali
  • 1,415
  • 2
  • 12
  • 26
  • Dup: http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java – skaffman Jun 07 '10 at 19:53
  • Best Answer on that dup that pertains to answering this question more specifically: https://stackoverflow.com/a/33072474/1357094 – cellepo Feb 03 '19 at 21:42
  • Still worth asking this as the other Question uses generic variable type `T` (not a concrete Class as here). – cellepo Feb 03 '19 at 21:58

4 Answers4

23

The simple answer: do not mix arrays with generics!

Use a list of hashsets:

ArrayList<HashSet<Integer>> rows = new ArrayList<HashSet<Integer>>();

The problem here is that Java specification doesn't allow you to declare an array of generics object.

A workaround of it is to use the wildcard, but you will lose the type-safety:

HashSet<?>[] rows = new HashSet<?>[9];

for (int i = 0; i < rows.length; ++i)
    rows[i] = new HashSet<Integer>();

This, in your case, won't create problems when you are going to check if an item is contained: you can easily do rows[0].contains(4) but when adding new content you will be forced to cast the row to the right type and suppress the warning of unchecked cast itself:

((HashSet<Integer>)rows[0]).add(4);

A side note: if you feel pioneer just download the Trove Collections framework that has a not-generics, highly optimized version of an integer hashset made to work with primitive type, I'm talking about the TIntHashSet class: it will solve your problem and you'll end up having faster code.

Jack
  • 125,196
  • 27
  • 216
  • 324
  • I am not mixing arrays with generics. How about HashSet[] rows = new HashSet[9]? – Murali Jun 07 '10 at 19:54
  • 2
    @wizard@: Yes you are (he means "don't mix them together", not "don't confuse one for the other.") If they are untyped, you'll just get raw-type warnings instead. That's no more correct. – Mark Peters Jun 07 '10 at 19:55
  • I liked your original answer better. – Justin Jun 07 '10 at 20:21
  • By declaring `rows` as `HashSet>` you are loosing all of the compile time checking you would get from having a generic typed declaration; at the expense of 'fixing' a single compiler warning. Its cast once (with a warning) or cast everywhere. – Justin Jun 07 '10 at 20:33
  • Actually I wouldn't never ever suggest to apply my solution. Since you shouldn't mix arrays and generics, that's all.. it was just for trivia :) – Jack Jun 07 '10 at 21:23
  • how to display the element for array of set? – SrividhyaShama Sep 29 '15 at 09:36
6

To quote Effective Java Second edition by Joshua Bloch, page 119

Because of these fundamental differences, arrays and generics do not mix well. For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter. None of these array creation expressions are legal: new List<E>[], new List<String>[], new E[]. All will result in generic array creation errors at compile time.

Why is it illegal to create a generic array? Because it isn’t typesafe. If it were legal, casts generated by the compiler in an otherwise correct program could fail at runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system.

(I omitted the part that explains Generic type erasure)

The Generics chapter of this book is available as a PDF.

Powerlord
  • 82,184
  • 16
  • 119
  • 164
4

You can declare the generic on the type declaration, but not when you actually allocate the object. Not sure the exact reason, perhaps to re-enforce the concept that some generics information is not preserved at compile time.

Set<Integer> rows[] = new HashSet[3];
for (int i = 0; i < rows.length; i++) {
 rows[i] = new HashSet<Integer>();
}
Justin
  • 4,271
  • 4
  • 29
  • 52
  • That both doesn't compile and gives warnings anyhow. To demonstrate the actual problem you would need to typecast rows to an `Object[]`, like `Object[] rows2 = rows`, noting that that doesn't generate a warning. – Mark Peters Jun 07 '10 at 19:57
  • I had a typeo, my original test used string. – Justin Jun 07 '10 at 20:22
1

Any time you're chaining generics or nesting data structures like this, it's time to take a step back and think about what you're really trying to do.

Would this be better if it were encapsulated in a wrapper class? It will probably make things less complex later. A week from now when you have to debug something in your array of hashsets of arraylists of arrays of some simple datatype because you thought you'd just keep wrapping them, you'll be sorry.

-edit: arrays are illegal? Point noted. I still feel the argument here stands.

You're using Java; don't be afraid to make some extra classes.

public class MyIntegers {
    private HashSet<Integer> theIntegers;

    // wrap methods
    public boolean add(Integer i) { return theIntegers.add(i); }
    public boolean contains(Integer i)...
    public boolean remove(Integer i)...

}

// later...
public static void main(String[] args) {
    MyIntegers[] rows = new MyIntegers[NUM_ROWS];
}
corsiKa
  • 76,904
  • 22
  • 148
  • 194
  • I like this answer much better. I was also just having this problem and tearing my hair out trying to get > to work with all the casting. I also tried nesting arraylists, but then you lose the nice [x] access, and have to call .get(x) instead. And sometimes installing add-ons isn't an option. – jsarma Mar 22 '14 at 15:36