Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is List<List<String>> an instance of Collection<Collection<T>>?

I wrote this handy, generic function for converting a collection of collections into a single set:

public static <T> Set<T> makeSet(Collection<Collection<T>> a_collection) {
    Iterator<Collection<T>> it = a_collection.iterator();
    Set<T> result = new HashSet<T>();
    while (it.hasNext()) {
        result.addAll(it.next());
    }
    return result;
}

Then I tried to call it:

    List<List<String>> resultLists = ... ;
    Set<String> labelsSet = CollectionsHelper.makeSet(resultLists);

and I received the following error:

<T>makeSet(java.util.Collection<java.util.Collection<T>>) in CollectionsHelper 
cannot be applied to (java.util.List<java.util.List<java.lang.String>>)

Now a List is a Collection, and a String is a T. So why doesn't this work and how do I fix it?

like image 573
Mark Ruzon Avatar asked Nov 20 '09 17:11

Mark Ruzon


People also ask

Is list a collection Java?

A List is an ordered Collection (sometimes called a sequence). Lists may contain duplicate elements. In addition to the operations inherited from Collection , the List interface includes operations for the following: Positional access — manipulates elements based on their numerical position in the list.

How do you create a collection string in Java?

Adding an element to a Collection is done via the add() method. Here is an example of adding an element to a Java Collection : String anElement = "an element"; Collection collection = new HashSet(); boolean didCollectionChange = collection. add(anElement);

How do I turn a list into a collection in Python?

Typecasting to list can be done by simply using list(set_name) . Using sorted() function will convert the set into list in a defined order.

Can you pass list String to list object?

Any Collection can be passed as an argument to the constructor as long as its type extends the type of the ArrayList , as String extends Object . The constructor takes a Collection , but List is a subinterface of Collection , so you can just use the List<String> .


1 Answers

Your signature should be:

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll);

Basically List<S> is not a subtype of List<T> just because S is a subtype of T. That property is called covariance and, in Java, generic types are not covariant (other languages such as scala contain covariant generic types).

What you did didn't work because it should be possible to add any Collection<T> into a Collection<Collection<T>>, so for example, with your signature, this would be a valid implementation:

public static <T> Set<T> makeSet(Collection<Collection<T>> coll) {
    coll.add(new HashSet<T>());
    return null;
}

But then calling this method as follows:

List<List<String>> outside = new LinkedList<List<String>>();
makeSet(outside); //actually this line will not compile!
List<String> oops = outside.get(0); //oh dear - it's a HashSet

So does this lead to the same problem? NO! The reason being that the compiler will not let you add anything into a collection parameterized on an unknown type:

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll) {
    coll.add(new HashSet<T>()); //this line will not compile
    return null;
}

Having wildcards was necessary in the first place so that you could do things like what you wanted to do, probably best demonstrated by how the Collection.addAll method was generified so that List<Number>.addAll(List<Integer>) would be allowed:

boolean addAll(Collection<? extends T> coll)
like image 111
oxbow_lakes Avatar answered Nov 06 '22 05:11

oxbow_lakes