I am trying to create a list of list of strings,
List<List<String>> string= new ArrayList<ArrayList<String>>();
and getting Type Mismatch error:cannot convert from ArrayList<ArrayList<String>> to List<List<String>>.
I know I can change
List<List<String>> to ArrayList<ArrayList<String>>
and it will work fine.
But I was just wondering why doesn't it let it happen? Simple List<Object> can refer to ArrayList<Object> so what is different about this?
Because a List<List<String>> would accept other lists of strings that were not array lists, which is not how you declared the type initially. For example, if you converted to a List<List<String>>, you would technically be allowed to add a LinkedList<String> to it! And that's not an ArrayList<String>. Allowing that cast would effectively break the generic type system.
In other words, you could convert to List<ArrayList<String>>. But not List<List<String>>.
List<List<String>> string = new ArrayList<List<String>>()
Would be the right way of do it.
Regards,
You cannot assign ArrayList<ArrayList<String>> to List<List<String>> because it violates the compile time type-safety promise of generics. If this assignment were valid, then we can insert LinkedList<String> into ArrayList<ArrayList<String>> and subvert the type-safety.
The canonical example of this is List<Number> is not List<Integer>. It can be shown easily by contradiction.
List<Integer> ints = new ArrayList<Integer>();
ints.add(42);
//This results in compiler error
/* List<Number> nums = ints; */
//If it were not and an error, then you could
List<Number> nums = ints;
//Now you can insert doubles into a list of `Number`s
nums.add(0.1);
//This would allow 0.1 to assign to an int
Integer x=ints.get(1);
//This will cause ClassCastException and
//violate type-safety provided by generics.
In addition to what guys have already said I'd like to notice that definition you wrote:
ArrayList>()
works for you but is not good enough.
You should say:
List> list = new ArrayList>();
The rule is never write concrete class into generics definition and in left part of assignment if there is an abstract class or interface. My version allows changing the list implementation in future without any changes in code that use this data structure.
Moreover List is a Collection. If it does not matter for you to use specific list's features (e.g. if you are going to only iterate over this list) you can say the following:
Collection> list = new ArrayList>();
In this case in future you even can change List to Set:
Collection> list = new LinkedHashSet>();
Related
I am confused with this behavior of Array List.
Can someone please explain this
List list = new ArrayList();
list.add(1);
list.add("test");
List<Integer> integerList = new ArrayList<>();
integerList.add(123);
integerList.add(456);
integerList.addAll(list);
System.out.println(integerList);
How can I add String in Integer arrayList
Can someone please share some resource to understand these things?
The reason is discussed here: Are generics removed by the compiler at compile time
Generics are checked by the compiler, but not afterwards during runtime.
As #user mentioned, your compiler/IDE will most likely show a warning e.g.
List is a raw type. References to generic type List should be parameterized
Why can I not declare a List of Lists like this?
List<List<Object>> a = new ArrayList<ArrayList<Object>>();
An ArrayList is of type List so I presumed that the above code would be valid.
This is valid though:
List<ArrayList<Object>> b = new ArrayList<ArrayList<Object>>();
The inner list has to be declared as ArrayList.
Can someone explain this?
You're confusing your generics. The way to do what you want is
List<List<Object>> a = new ArrayList<List<Object>>();
By using ArrayList within the generic parameter, you're narrowing the scope of the object from List to ArrayList, thereby changing the generic signature. By using ArrayList outside the generic, you're still conformant; you're specifying which implementation of List you want to use, and that the objects it will hold are of type List<Object>, exactly as the left hand side states.
To see why this is important, consider this list:
// Invalid declaration, but pretend it is valid
List<List<Object>> a = new ArrayList<ArrayList<Object>>();
a.add(new ArrayList<Object>()); // valid
a.add(new LinkedList<Object>()); // not valid because it's not an ArrayList;
// but according to the left side, it is valid!
Of course, the best method is to use Java 7's diamond operator:
List<List<Object>> a = new ArrayList<>();
This is not as much a problem with the inner list as it is the problem of the generic parameter. As long as the generic parameter is the same (i.e. ArrayList<Object>) the initialization succeeds. Otherwise, Java does not let you make an assignment, because the compiler cannot guarantee type safety.
Imagine that this is possible:
// Let's pretend this compiles:
List<List<Object>> a = new ArrayList<ArrayList<Object>>();
Now the following must be valid:
a.add(new LinkedList<Object>());
However, this is invalid, because the object is an ArrayList of ArrayLists, so inserting a linked list into it is clearly invalid.
You can do this, however:
List<List<Object>> a = new ArrayList<List<Object>>();
This should be good enough to program to the interface.
I just start to learn Java and I am getting "#SuppressWarnings("unchecked")"
I am sure that one of my static variable is making trouble
static ArrayList<Integer>[] docNumber = (ArrayList<Integer>[]) new ArrayList[20];
eclipse said "Type safety: Unchecked cast from ArrayList[] to ArrayList[]"
but i am not really sure how to avoid this problem
can you tell me how to fix this problem?
thanks
Can't be avoided with arrays.
Use a List<List<Integer>> instead.
In order to avoid the #SuppressWarnings(“unchecked”) you should give the compiler the information needed to perform all type checks that would be necessary to ensure type safety, see unchecked FAQ.
In your case, I assume that you are trying to maintain a list of document integers, for this you will need:
List<Integer> docNumber=new ArrayList<Integer>();
If you would like to keep a list of lists then you can do:
List<List<Integer>> docNumber=new ArrayList<List<Integer>>();
Are you trying to achieve this (List of Array Of Integer)?
static ArrayList<Integer[]> docNumber = new ArrayList<Integer[]>();
In general to decalre the arrayList we can declare as below.
ArrayList Obj = new ArrayList();
This is correct only. But in our code we will not do like this.we do as below
List Obj = new ArrayList();
Why we will do like this? Why Upcasting ?
And While Upcasting we are restricting its functionality. Any specific reason we declare ArrayList or LinkedList like this?
Yes - because unless you need the specific functionality only exposed via the concrete type, it's generally a good idea to refer to the more general type. That way, if you ever decide to use a different implementation, you know that you're not tied to anything specific to the current implementation. You can later change the single statement:
List<String> list = new ArrayList<String>();
to (say)
List<String> list = new LinkedList<String>();
and know that everything will still compile. Of course the behaviour can change in terms of performance, thread safety etc - but that would be the case anyway.
You're also expressing that you don't need any members which are specific to ArrayList<String>, which can be important when reading the code later.
All of this is particularly relevant when it comes to picking the return type and parameter types of methods. The more specific you are about a return type, the less flexibility you have to change the implementation later. The more specific you are about a parameter type, the less flexibility you give your callers.
The point is that ArrayList and LinkedList are both used as lists. Our program logic shouldn't rely on how they store the list, just that they can be used to store items in an ordered way, which can be accessed based on that fact.
It is not upcasting. It is the right way to work. Actually when you are using List it does not matter how is it implemented. It is important that it is list. All method you are using are defined in interface. The same is correct for all other classes. Always try to use interface in the left side of assignment operator and in interfaces you define. In this case it will be easy to change ArrayList to LinkedList. Just change it in one place: replace new ArrayList by new LinkedList and you are done.
Moreover in most cases you even do not need List. if then you only iterate over the elements it is enough to use Collection. Because Collection interface is implemented by both lists and sets. So in future if you will prefer to store your elements in set you will again have to perform only one change.
The definitive answer can be found in
Joshua Bloch's Effective Java, Item 52: Refer to objects by their interfaces.
Its plain and simple - Polymorphism
You program to a more general or abstract class or interface type like List, and Java's polymorphic behavior will be able to automatically find out at runtime what actual definiton the implemented object belongs to. Here List is an interface.
Polymorphism helps in maintenance and refactoring without much hassle. If you know Polymorphism, you will know this.
ArrayList<String> list;
list = new ArrayList<String>(); //possible
list = new LinkedList<String>(); //not possible
LinkedList<String> list;
list = new ArrayList<String>(); //not possible
list = new LinkedList<String>(); //possible
but
List<String> list;
list = new ArrayList<String>(); //possible
list = new LinkedList<String>(); //possible
to increase this possibility u need to practice this actually :P
Example and use with below example :-
public static List<Integer> intList;
public static List<Integer> ArrayListDemo() {
intList = new ArrayList<>();
intList.add(100);
intList.add(200);
intList.add(500);
return intList;
}
public static List<Integer> LinkedListDemo() {
intList = new LinkedList<>();
intList.add(10);
intList.add(20);
intList.add(50);
return intList;
}
public static void main(String[] args) {
System.out.println(ArrayListDemo());
System.out.println(LinkedListDemo());
}
}
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);