-1

I want to create an array of ArrayLists, similar to that in this thread: How to do an array of hashmaps?. However, Java gives the warning

"Cannot create a generic array of ArrayList<String>"

when I try to do the following ArrayList[] arrayOfLists = new ArrayList[size];

I have sort of understood the problems and the workarounds provided. I have my own approach which unfortunately does not fix the problem either.

I tried creating a list of ArrayLists and then used toArray().

ArrayList<ArrayList<String>> listOfLists = new ArrayList<ArrayList<String>>();  
ArrayList<String>[] arrayOfLists = (ArrayList<String>[])listOfLists.toArray();

Worked fine, but got the warning :

Type safety: Unchecked cast from Object[] to ArrayList<String>[]

When I tried to check for type safety, using

if(listOfLists.toArray() instanceof ArrayList<String>[]) 

I get the error:

Cannot perform instanceof check against parameterized type ArrayList<String>[]. Use the form ArrayList<?>[] instead since further generic type information will be erased at runtime

Why cant I use this method? Why does toArray() return Object[] instead of ArrayList<String> since the instance was initialised with theArrayList<String>; type?
Any other workarounds/suggestions on how I can get this done? A 2D array will not work since different lists can vary greatly in size.

Community
  • 1
  • 1
TSG
  • 877
  • 1
  • 6
  • 23
  • Hint: Code is not escaped as `<` etc. Just put your code in the question and indent it with four spaces. It is not necessary to write HTML. –  Jul 08 '14 at 09:43
  • Short answer, you can't. You could create a list of lists instead. – Kayaman Jul 08 '14 at 09:45
  • `ArrayList[] arrayOfLists =(ArrayList[])listOfLists.toArray();` can you check if this work? – bumbumpaw Jul 08 '14 at 09:45
  • 1
    May be useful: [Can I create an array whose component type is a concrete parameterized type?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ104) – izstas Jul 08 '14 at 09:47
  • There is a typo in your code `ArrayListString>> listOfLists` -> `ArrayList> listOfLists` – Mustafa sabir Jul 08 '14 at 10:05

2 Answers2

2

The currently accepted answer has a major error in describing Java's generics, so I felt I should answer to make sure there aren't any misconceptions.

Generics in Java are an entirely compile-time feature and for the most part don't exist at runtime due to erasure (you can get the runtime to cough up generic type information in some cases, but that's far from the general case). This provides the basis for the answers to your questions.

Why cant I use this method?

Because generics are erased, an ArrayList<String>[] (as well as all other parameterized ArrayList<>[] instances) at runtime is really an ArrayList[]. Thus, it is impossible for the runtime to check if something is instanceof ArrayList<String>[], as the runtime doesn't actually know that String is your type parameter -- it just sees ArrayList[].

Why does toArray() return Object[] instead of ArrayList since the instance was initialised with theArrayList; type?

Again, erasure. The type parameter is erased to Object, so at runtime what you effectively have is an ArrayList<Object>. Because of this erasure, the runtime doesn't have the information necessary to return an array of the proper type; it only knows that the ArrayList holds Objects, so it returns an Object[]. This is why the toArray(T[]) overload exists -- arrays retain their type information, so an array could be used to provide the requisite type information to return an array of the right type.

Any other workarounds/suggestions on how I can get this done?

As you can see, mixing generic stuff and arrays doesn't work too well, so ideally, you wouldn't mix Lists and arrays together. Therefore, if possible, you should use List<List<String>> or something of the sort instead of List<String>[]. If you want to keep a ArrayList<String>[], though, you could do this:

@SuppressWarnings("unchecked")
ArrayList<String>[] array = new ArrayList[size];

You'll still get the unchecked type warning, but you can be reasonably sure that you won't encounter heap pollution as the only reference to the object is through array. You can also use this as the parameter to toArray():

@SuppressWarnings("unchecked")
ArrayList<String>[] temp = new ArrayList[0];
ArrayList<String>[] arrayOfLists = listOfLists.toArray(temp);

or

@SuppressWarnings("unchecked")
ArrayList<String>[] arrayOfLists = listOfLists.toArray((ArrayList<String>[]) new ArrayList[0]);

For more reading on why you can't parameterize an array, see this SO question. In short, such a thing isn't safe because arrays are covariant, while generics are invariant.

awksp
  • 11,764
  • 4
  • 37
  • 44
0

The problem is that Generics are created during runtime, but type conversions and array sizes must be checkable at compile time. The compiler cannot tell what class ArrayList<String> will be during compile time (as it will be generated later), it can only tell that it will be at least an Object, because every class in Java is at least an Object. You can do type conversion and suppress the warning and it might even work, but you run into a pitfall to accidentally confuse types somewhere and mess up your code.

Java is a type-safe language by choice to prevent you from doing one of the most recurring mistakes programmers do in their daily work: confusing variable types. So while it is possible to do the type conversion, you - as an upcoming good Java programmer - should not do that. Use the ArrayList<ArrayList<String>> if you need such a construct, and use arrays only when they are necessary.

The main reason to use arrays is speed of execution, as obviously using an object will keep the runtime busy with some overhead. The main reason to not use arrays is the fact that this overhead will allow you more flexibility in coding and reduce the amount of errors you make. So as a general advice: unless you know (as in measured and determined to be a bottleneck) that you need the speed, go with Lists. Java even does some internal optimizations beyond what you would expect to speed up Lists to a point where they come very close to the execution speed of arrays.

TwoThe
  • 13,879
  • 6
  • 30
  • 54
  • This isn't really correct; Java's generics pretty much *don't exist* at runtime. You may be mixing them up with the generic system for a different language. – awksp Jul 09 '14 at 15:07