Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't you have a "List<List<String>>" in Java? [duplicate]

In Java, why doesn't the following line of code work?

List<List<String>> myList = new ArrayList<ArrayList<String>>();

It works if I change it to

List<ArrayList<String>> myList = new ArrayList<ArrayList<String>>();

At first, I thought maybe you can't have lists of an interface, but I can create a List<Runnable> just fine.

Ideas?

like image 489
Nosrettap Avatar asked Oct 12 '12 14:10

Nosrettap


People also ask

Does a list allow duplicates?

List allows duplicates while Set doesn't allow duplicate elements . All the elements of a Set should be unique if you try to insert the duplicate element in Set it would replace the existing value. List permits any number of null values in its collection while Set permits only one null value in its collection.

Can we add one list to another list in Java?

It is possible to add all elements from one Java List into another List . You do so using the List addAll() method.

How do I make a list of strings in Java?

We can create List as: List<String> arrayList = new ArrayList<>(); List<String> linkedList = new LinkedList<>(); We can also create a fixed-size list as: List<String> list = Arrays.


4 Answers

Generic types are more pedantic.

List means List or any sub-type, but <List> means only List. If you want a sub-type you need to have <? extends List>

I suspect you can use

List<List<String>> myList = new ArrayList<List<String>>();

The reason you can't do this is that you can be using a reference to a reference and with an extra level of indirection you have to be careful.

// with one level of indirection its simple.
ArrayList alist = new ArrayList();
List list = aList; // all good
list = new LinkedList(); // alist is still good.

With generics you can have two level of indirection which can give you problems so they are more pedantic to avoid these issues.

// with two levels of indirection
List<ArrayList> alist = new ArrayList<ArrayList>();
List<List> list = (List) alist; // gives you a warning.
list.add(new LinkedList()); // adding a LinkedList into a list of ArrayList!!
System.out.println(alist.get(0)); // runtime error

prints

Exception in thread "main" java.lang.ClassCastException: java.util.LinkedList
     cannot be cast to java.util.ArrayList
like image 123
Peter Lawrey Avatar answered Oct 21 '22 05:10

Peter Lawrey


Lets start with this:

    ArrayList<ArrayList<String>> myList = new ArrayList<ArrayList<String>>();

This is creating an ArrayList whose elements are ArrayLists.

Now suppose we could assign that to

    List<List<String>> myList2 = myList.

Now, we should be able to do this:

    myList2.add(new LinkedList<String>());

But that means we have added a LinkedList to a list whose elements are supposed to be ArrayLists. Ooops!!!

In reality, the assignment of myList to myList2 is not legal ... and that ensures that it is not possible to add the wrong kind of List<String> to the ArrayList<ArrayList<String>> object. (No Peter, it is not just pedantry :-) )

like image 21
Stephen C Avatar answered Oct 21 '22 05:10

Stephen C


Only the top level collection can be declared as an implementing class, while the nested ones must remain interfaces until you actually create instances:

List<List<String>> rootList = new ArrayList<List<String>>(); 

and then when you create an element to go in, you make it an implementation:

List<String> nodeList = new ArrayList<String>();
rootList.add(nodeList);
like image 45
amphibient Avatar answered Oct 21 '22 03:10

amphibient


Its comparing Type from left(declaration) side to Type from right(instantiation) side. In Left, your type is List<String> while in right, it's ArrayList<String>. If complaining about the difference.

Please update the right side(instatiation) as List i.e.

   List<List<String>> myList = new ArrayList<List<String>>();

This should work fine.

like image 39
Yogendra Singh Avatar answered Oct 21 '22 03:10

Yogendra Singh