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").
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);
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>>
I know its a bit late to reply but I found this workaround helpful for my case...Hope it helps!
Use an array of HashMap to store HashMaps..
public static void main(String[] args) {
HashMap[] arr = new HashMap[1];//creating an array of size one..just for sake of example
HashMap<String, String> arrMap = new HashMap<String, String>();
//use loops to store desired key-value pairs into the HashMap which will be stored inside the array
arrMap.put("ABC", "Name");
//use loop to store your desired hashMap into the array at a particular index
arr[0] = arrMap;
//desired manipulation of the stored array.
System.out.println(arr[0]);
}
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);
Related
I faced a problem yesterday, when I was writing my homework. I finished the homework, but I still don't really understand why my code works. I had to write a sort function that takes an varargs of any comparable generic object as an argument and return the argument. The problem was that I had to return an array of sorted objects. So I had to learn more about varargs lists and arrays.
The function was defined like this.
public <T extends Comparable<T>> T[] stableSort(T ... items)
and inside the function I made a list, which I would sort and do all the work on.
List<T> list = new ArrayList<T>(Arrays.asList(items));
and at the end of the function I was returning list toArray so that it matched the output type T[].
list.toArray(items.clone());
My question is since I already made the list from the varargs, why do I have to do items.clone() inside the toArray function. That seemed like doing two same things to me. I thought arrays.asList() would clone the values of array to list and I don't get why am I doing it again at the end of the code in toArray(). I know that this was the correct way to write it, because I finished the homework yesterday and found out this way from forums of the class, but I still don't understand why.
EDIT
The task required me to create a new array with sorted files and return it instead. Due to Type Erasure, it is not possible to instantiate an array of a generic type without a reference to a class that fits the generic. However, the varargs array has type T, so I should have cloned an array of a type which fits the generic constraints. Which I didn't know how to do in time. So I decided to use list to make my time easier till the deadline.
My question is since I already made the list from the varargs, why do I have to do items.clone()
You are right. Unfortunately, the compiler will be unable to determine the type of the array if you simply use the toArray() method. You should get a compilation error saying Cannot convert from Object[] to T[]. The call to item.clone() is required to assist the compiler in type-inference. An alternate approach would be to say return (T[])list.toArray
That said, I would not recommend either of the approaches. It doesn't really make sense to convert an array to a list and convert it back to an array in the first place. I don't see any significant take-aways that you would even understand from this code.
It seems to me there are a few questions here, that may have come together to create some confusion as to why what needs to be done.
I thought arrays.asList() would clone the values of array to list and I don't get why am I doing it again at the end of the code in toArray().
This is probably just the way it is typed, but it should be made clear that you don't clone the objects in the array, but only make a new List with the references to the objects in the array. The objects themselves will be the same ones in the array as in the List. I believe that is probably what you meant, but terminology can be tricky here.
I thought arrays.asList() would clone the values of array to list...
Not really. Using Arrays.asList(T[] items) will provide a view onto the array items that implements the java.util.List interface. This is a fixed-size list. You can't add to it. Changes to it, such as replacing an element or sorting in-place, will pass through to the underlying array. So if you do this
List<T> l = Arrays.asList(T[] items);
l.set(0, null);
... you've just set the element at index 0 of the actual array items to null.
The part of your code where you do this
List<T> list = new ArrayList<T>(Arrays.asList(items));
could be written as this:
List<T> temp = Arrays.asList(items);
List<T> list = new ArrayList<T>(temp);
The first line is the "view", the second line will effectively create a new java.util.ArrayList and fill it with the values of the view in the order they are returned in by their iterator (which is just the order in the array). So any changes to list that you make now don't change array items, but keep in mind that it's still just a list of references. items and list are referencing the same objects, just with their own order.
My question is since I already made the list from the varargs, why do I have to do items.clone() inside the toArray function.
There could be two reasons here. The first is as CKing said in his/her answer. Because of type erasure and the way arrays are implemented in Java (there are separate array types depending on whether it's an array of primitives or references) the JVM would not know what type of array to create if you just called toArray() on the list, which is why that method has a return type of Object[]. So in order to get an array of a specific type, you must provide an array to the method that can be used at run-time to determine the type from. This is a piece of the Java API where the fact that generics work via type-erasure, aren't retained at run-time and the particular way in which arrays work all come together to surprise the developer. A bit of abstraction is leaking there.
But there might be a second reason. If you go check the toArray(T[] a) method in the Java API, you'll notice this part:
If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
Suppose some code by another dev is using your stableSort method like this:
T[] items;
// items is created and filled...
T[] sortedItems = stableSort(items);
If you didn't do the clone, what would happen in your code would be this:
List<T> list = new ArrayList<T>(Arrays.asList(items));
// List is now a new ArrayList with the same elements as items
// Do some things with list, such as sorting
T[] result = list.toArray(items);
// Seeing how the list would fit in items, since it has the same number of elements,
// result IS in fact items
So now the caller of your code gets sortedItems back, but that array is the same array as the one he passed in, namely items. You see, varargs are nothing more than syntactic sugar for a method with an array argument, and are implemented as such. Perhaps the caller didn't expect the array he passed in as an argument to be changed, and might still need the array with the original order. Doing a clone first will avoid that and makes the effect of the method less surprising. Good documentation on your methods is crucial in situations like this.
It's possible that code testing your assignment's implementation wants a different array back, and it's an actual acquirement that your method adheres to that contract.
EDIT:
Actually, your code could be much simpler. You'll achieve the same with:
T[] copy = items.clone();
Arrays.sort(copy);
return copy;
But your assignment might have been to actually implement a sorting algorithm yourself, so this point may be moot.
You need to use this:
List<T> list = new ArrayList<T>(Arrays.asList(items));
when you want to do an inline declaration.
For example:
List<String> list = new ArrayList<String>(Arrays.asList("aaa", "bbb", "ccc"));
By the way, you didn't have to use return list.toArray(items.clone()); You could have used, for example, return list.toArray(Arrays.copyOf(items, 0));, where you are passing to list.toArray() an empty array that contains none of the arguments from items.
The whole point of passing an argument to the version of list.toArray() that takes an argument, is to provide an array object whose actual runtime class is the actual runtime class of the array object it wants to return. This could have been achieved with items.clone(), or with items itself (though that would cause list.toArray() to write the resulting elements into the original array pointed to by items which you may not want to happen), or with, as I showed above, an empty array that has the same runtime class.
By the way, the need to pass the argument to list.toArray() is not a generics type issue at all. Even if you had written this with pre-generics Java, you would have had to do the same thing. This is because the version of List::toArray() that took no arguments always returns an array object whose actual runtime class is Object[], as the List doesn't know at runtime what its component type is. To have it return an array object whose actual runtime class is something different, you had to give it an example array object of the right runtime class to follow. That's why pre-generics Java also had the version of List::toArray() that took one argument; even though in pre-generics, both methods were declared to return Object[], they are different as the actual runtime class returned is different.
What's the difference between using a typed vs. non-typedArrayList in Java?
For example, Using an ArrayList of CustomObject:
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject);
or non-typed:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred? Is there any difference when the ArrayList is holding different datatypes, e.g. an ArrayList of String, Int, etc.?
In the Second Approach, it is not mandatory to add only CustomObject whereas it is in 1st Approach, otherwise, you will get Compilation Error.
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject());
This approach is generally preferable as there are no chances of having Class Cast Exception but in second approach there are high chances of that !!
JavaDocs explains it beautifully : Why to prefer Generics
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement generic algorithms.
It's never preferable to use the latter option. I don't think that is even possible. I think you meant:
ArrayList nonTypedArray = new ArrayList();
This syntax is left over from Java 1.4 and earlier. It still compiles for the purposes of backwards compatibility.
Generics was introduced in Java 1.5 which allowed you to specify the types between angled brackets.
It is always preferable to use generics because it is more type-safe.
That is, if you specify
ArrayList<String> typedArray = new ArrayList<String>();
Then you cannot accidentally add an integer to this array list; if you tried to add an integer, the program would not compile.
Of course, Generics ensures type safety at compile time. At runtime ArrayList<String> typedArray = new ArrayList<String>(); becomes ArrayList typedArray = new ArrayList();. This is to maintain backwards compatibility.
What's the difference between using a typed vs. non-typed ArrayList in
Java?
A typed/generic ArrayList is a collection of objects in which the "type" of the object is defined in angled brackets. Generics were introduced in Java 5 to create type-safe collections.
Before Generics the collection was called untyped/raw type collection because there was no way to specify the compiler the type of the collection being created.
The difference between both is to detect type-safe operations at compile time.
In both of your cases, you are adding object(s) of type 'CustomObject' to the ArrayList. There will be no issue while adding elements in the list, as both lists will consider them as typed objects.
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<CustomObject>();
typedArray.add(new CustomObject);
Untyped:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred?
I don't think so. As generics are recommended to be used while creating a list to ensure type-safe operations.
Is there any difference when the ArrayList is holding different
datatypes, e.g. an ArrayList of String, Int, etc.?
Surely, there is a reasonable difference. For an untyped list, you will need to add type-cast while fetching elements from a list. As there is a possibility of the compiler throwing a ClassCastException at runtime due to different types of elements.
In runtime, there is absolutely no difference, however in compilation time, using type parameters can save you from a plethora of errors, so it is always preferable to use generics properly.
The only case where raw types are used reasonably is in legacy applications, but even in this case, you try to use typed parameters if you can.
The use of type simplifies your coding removing the need of casting and also stores your data efficiently
https://docs.oracle.com/javase/tutorial/java/generics/why.html
Yeah, I know this is an old post. But I wanted to share an instance where an untyped ArrayList is useful: when you're writing a function that supposed to act on arbitrary element types. For example, suppose you want to make a generic shuffle function that knows how to shuffle an array. Like so:
ArrayList<Die> diceRolls = getGetPossibleDiceRolls();
ArrayList<Card> cardDeck = getPossibleCards();
ArrayList<GirlToDate> blackbook = getBlackbook();
shuffle(diceRolls);
shuffle(cardDeck);
shuffle(blackbook);
.
.
void shuffle(ArrayList array) {
int size = array.size();
for (int i=0; i<size; ++i) {
int r = random.nextInt(size - i) + i;
// Swap
Object t = array.get(i);
array.set(i, array.get(r));
array.set(r, t);
}
}
Some might argue "yeah, but the proper way to do this is to create an interface or subclass of something like a Shuffleable type..." But really?
In Java 1.7 and upwards you should normally use the constructor like this:
ArrayList<MyObject> list = new ArrayList<>();
or else for a more general List object:
List<MyObject> list = new ArrayList<>();
Observe that you only specify the type <MyObject> once, not twice. This makes your code easier to maintain. The <> causes the constructor to return an ArrayList which is already typed to match the field/variable to which it is being assigned - so that no cast will be required in the calling code.
Do not use new ArrayList() as the constructor. This returns an untyped ArrayList which then has to be cast to a type to match the field/variable to which it is being assigned. This means unnecessary type checking and casting and so generally reduces performance.
recently I read a piece of code which seems weird to me. As we know, we need to initialize the generic type in collections when we need to use them. Also, we know Collections can contain Collections as their elements.
The code:
public class Solution {
public static void main(String args[]) {
ArrayList res = returnlist();
System.out.print(res.get(0));
}
public static ArrayList<ArrayList<Integer>> returnlist() {
ArrayList result = new ArrayList();
ArrayList<Integer> content = new ArrayList<Integer>();
content.add(1);
result.add(content);
return result;
}}
My question is
why can we use ArrayList result = new ArrayList(); to create an object, since we have not gave the collection the actual type of element.
why can we use result.add(content); to add a collection to a collection with collection "result" is just a plain collection. We have not defined it as a ArrayList of ArrayList
Java generic collections are not stored with a type to ensure backwards compatibility with pre J2SE 5.0. Type information is removed when added to a generic collection. This is called Type Erasure.
This means that a generic collection can be assigned to a non generic reference and objects in a generic typed collection can be placed in an non generic, nontyped collection.
All Java generics really does is make sure you can't add the wrong type to a generic list and saves you from doing an explicit cast on retrieval; even though it is still done implicitly.
Further to this
the Java section of this answer goes a little deeper into what I just said
this article also covers basically what you were asking in a more complete way
other things to watch out for with Type Erasure
Just adding up to provide summarized answer
Old way :
(A) ArrayList result = new ArrayList();
will create an Arraylist to hold "Object"
New Way :
ArrayList<Integer> content = new ArrayList<Integer>();
this represents an Arraylist which will hold "Integer" objects. This was introduced for compile-time type check purposes.
why ?
Consider the first case. Its input type is Object. We know that Object is the super class of all classes. We can pass in an Integer object, String object and so on. When fetching the data the developer has to perform proper type casting. Say if the developer initially thinks the code will accept Integer objects so he adds the following typecast while fetching the data
Integer integer=(Integer) content.get(0);
This is supposed to work. But if mistakenly he passes a String it will result in run-time error.
How it can be avoided ?
By introducing compile time checks
How it works ?
when we specify parameterized type only Integer objects can be added to the ArrayList collection. Else it will show error.
content.add(3); // will work
content.add("HARSHAD"); // error shown
If parameterized generic types are for type checking purposes how correct data can be retrieved from the list ?
The compiler implicitly performs type conversion. See the sample code
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
Integer integer=list.get(0);
System.out.println(integer);
What the compiler actually does when you perform compilation ?
//perform type erasure
(B) List list=new ArrayList();
list.add(1);
list.add(2);
// the arraylist inturn accepts Object when you run the code
//add casting
Integer integer=(Integer)list.get(0);
Conclusion
If you see the codes (A) and (B) both are the same. Only difference is that in the second case the compiler implicitly does the same operation.
Finally to answer your question ...
ArrayList result = new ArrayList();
is allowed for backward compatibility purposes. Although this is not recommended.
Official link from Oracle docs explaining the same concept.
Generics were added to Java only in Java 5. Before that, when you use a collection, it always meant collection of objects. The old syntax is left as is for backward compatibility. So ArrayList result = new ArrayList() is actually creating an ArrayList<Object>. Since ArrayList is also an object, you can add content to the variable result.
why can we use ArrayList result = new ArrayList(); to create an object, since we have not give the collection the actual type of element.
Because java wants to it backward compatible. Generics is more of compiler feature for ensure type safety, collections can store any type of object at runtime.
Java compiler will not give you compiler error for this but it must have given you compiler warning that it is unsafe to use generic classes without type.
It may be a remnant from before generics came along to java (Java 4 or 5 I think).
I am iterating over a List of Lists. In my code listofuserdetailsperAccount is List<List>. I am considering the two methods below, please let me know which way is correct, more efficient and should be followed in java coding.
Way 1-----
for(int i=0;i<=listofuserdetailsperAccount.size();i++){
List list=(List) listofuserdetailsperAccount.get(0);
}
Way 2---
for(int i=0;i<=listofuserdetailsperAccount.size();i++){
List list= new ArrayList();
list=(List) listofuserdetailsperAccount.get(0);
}
I'll go with for each loop
for( List userDetailsPerAccount : listOfUserDetailsPerAccount ) {
//anything you want to do with userDetailsPerAccount
}
Way 1 is better approach than Way 2. In Way 2 List list= new ArrayList(); it will create a extra ArrayList object which does not have any use, which will cause memory consumption for sometime.
And it is also recommended use type specific List<E> so that you dont cast at runtime it will be typesafe.
for(List<E> list : listOfUserDetailsPerAccount){
...
}
In Java 5 and above use for-each.
You have a couple of problems here, with both proposed solutions.
Your List<List> listofuserdetailsperAccount object is not properly typed, as the inner List is a raw type, something to be avoided. Assuming your inner list holds UserDetail objects, your list of lists should be of type List<List<UserDetail>>.
You don't use the for-each loop syntax to iterate over a List, which is Iterable.
for(List<UserDetail> innerList : listofuserdetailsperAccount)
In Way 2 you initialize List to a new ArrayList (which is a raw type, it should be new ArrayList<>() if you needed this) and then promptly overwrite this value with the contents of your outer list. This means you ask Java to construct a new object that is then immediately cleaned up by the garbage collector, unused. This is wasteful and unnecessary.
In summary, you likely want to do:
List<List<UserDetail>> listofuserdetailsperAccount = // initialize your list
for(List<userDetail> innerList : listofuserdetailsperAccount) {
// do work with your innerList now
}
You commented (tidied up):
So while initializing I am doing something like this now, can you please let me know if this is correct:
List<List<String>> listofAccountdetailsLoggedinUser = null;
listofAccountdetailsLoggedinUser = new ArrayList<List<String>>();
OR I should not put it as null and directly create an object like this:
List<List<String>> listofAccountdetailsLoggedinUser =
new ArrayList<List<String>>();
That is the right track, but you do not need to initialize the variable to null. It doesn't hurt anything, since it doesn't construct an unnecessary object, but there's no reason to - you can declare and initialize the variable in one line, like you do in your second example.
Additionally, you don't need to specify the type of the ArrayList on the right hand side, simply use the diamond operator <>, like so:
List<List<String>> listofAccountdetailsLoggedinUser = new ArrayList<>();
Also, consider a shorter variable name, there's no need to use such a long one, and it's no fun to type :)
When compiling a short piece of java code I get a compilation note of having unsafe operations. I basically just was hoping for the concept of how to change my data structure that would make it safe.
The concept: I need to organize inputed strings into buckets based on their length, which could be arbitrary (although less than 80 chars).
The Code:
Map<Integer, List> buckets = new HashMap<Integer, List>();
if(!buckets.containsKey(length))
{
buckets.put(length,new Vector<wordValues>());
}
//Now add the temp to the bucket
buckets.get(length).add(new wordValues(temp));
And then I add the string to the list corresponding to its size.
What would be a better way to do this?
You mix raw and Generics List, try:
Map<Integer, List<wordValues>> buckets = new HashMap<Integer, List<wordValues>>();
Also, usually class names start with upper case, e.g. WordValues.
The problem is that you're using the raw type List rather than the parameterized generic type List<WordValues>.
Generics are covered extensively in the Oracle Java Tutorials.
Map<Integer, List<WordValues>> buckets = new HashMap<>();
...
List<WordValues> values = buckets.get(length);
if (values == null) {
values = buckets.put(length, new ArrayList<WordValues>());
}
values.add(new WordValues(temp));
Some tid-bits:
containsKey and get both do identical look-ups. It seems kinda odd to do the it twice :-p
Avoid using Vector in favor of ArrayList. If you need it to be synchronized, consider decorating it via Collections.synchronizedList.
Collections.synchronizedList(new ArrayList<WordValues>())
Java 7 supports type parameter inference which can significantly ease the burden on you. Notice above I didn't have to type HashMap<Integer, List<WordValues>>; instead, I merely typed HashMap<>, taking advantage of the new diamond operator.
Avoid using class names that begin with a lower-case character; this is generally hard to read (and against the Oracle Code Conventions). Consider naming your class WordValues rather than wordValues.