I can declare an array of maps using generics to specify the map type:
private Map<String, Integer>[] myMaps;
However, I can't figure out how to instantiate it properly:
myMaps = new HashMap<String, Integer>[count]; // gives "generic array creation" error
myMaps = new HashMap[count]; // gives an "unchecked or unsafe operation" warning
myMaps = (Map<String, Integer>[])new HashMap[count]; // also gives warning
How can I instantiate this array of maps without getting a compiler error or warning?
Update:
Thank you all for your replies. I ended up going with the List suggestion.
Not strictly an answer to your question, but have you considered using a List
instead?
List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
seems to work just fine.
See Java theory and practice: Generics gotchas for a detailed explanation of why mixing arrays with generics is discouraged.
Update:
As mentioned by Drew in the comments, it might be even better to use the Collection interface instead of List
. This might come in handy if you ever need to change to a Set
, or one of the other subinterfaces of Collection
. Example code:
Collection<Map<String,Integer>> maps = new HashSet<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
From this starting point, you'd only need to change HashSet
to ArrayList
, PriorityQueue
, or any other class that implements Collection
.
You can't safely create a generic array. Effective Java 2nd Edition goes into the details in the chapter on Generics. Start at the last paragraph of page 119:
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.
To make this more concrete, consider
the following code fragment:
// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
Let’s pretend that line 1, which
creates a generic array, is legal.
Line 2 creates and initializes a
List<Integer>
containing a single
element. Line 3 stores the
List<String>
array into an Object
array variable, which is legal because
arrays are covariant. Line 4 stores
the List<Integer>
into the sole
element of the Object
array, which
succeeds because generics are
implemented by erasure: the runtime
type of a List<Integer>
instance is
simply List
, and the runtime type of a
List<String>[]
instance is List[]
, so
this assignment doesn’t generate an
ArrayStoreException
. Now we’re in
trouble. We’ve stored a List<Integer>
instance into an array that is
declared to hold only List<String>
instances. In line 5, we retrieve the
sole element from the sole list in
this array. The compiler automatically
casts the retrieved element to String
,
but it’s an Integer
, so we get a
ClassCastException
at runtime. In
order to prevent this from happening,
line 1 (which creates a generic array)
generates a compile-time error.
Because arrays and generics don't combine well (as well as other reasons), it's generally better to use Collection
objects (in particular List
objects) rather than arrays.
In general it is not a good idea to mix generics and arrays in Java, better use an ArrayList.
If you must use an array, the best way to handle this is to put the array creation (your example 2 or 3) in a separate method and annotate it with @SuppressWarnings("unchecked").
Short answer appears to be that you really just can't.
See the following for a blog about it.
http://www.bloggingaboutjava.org/2006/01/java-generics-quirks/
One of the comments to the blog states that:
Actually, the engineers made the creation of such an Array illegal. So the creation of an array from generic Class fails. The Collection.toArray method followed by a Cast to the Array works at compile time.
This solves not the problem, that the ArrayStoreCheck can’t be done during Runtime, but you can create an Array of generics in this way.
As suggested by Bill the Lizard, you probably are better off using a
List<Map<String,Integer>>
You can create generic array of map
Create list of map.
List<Map<String, ?>> myData = new ArrayList<Map<String, ?>>();
Initialize array.
Map<String,?>[]myDataArray=new HashMap[myData .size()];
Populate data in array from list.
myDataArray=myData.toArray(myDataArry);
I had a similar question, best response I got referred to this
myMaps = new HashMap<String, Integer>[10]();
So that's Wrong
Why not make a List of Maps instead of trying to make an array?
List<Map<String, Integer>> mymaps = new ArrayList<Map<String, Integer>>(count);