1

I defined a generic function in java with the signature

<V> List<V> sortedValuesFromMap(Map<?, Collection<V>> keysValues, Comparator<V> comp)

which takes a Map mapping any type of keys to a Collection of some defined type V, and a comparator of type V. The method works great and the Java compiler does not complain about type incompatibility.

But now when I want to apply this method to a map of the type Map<String, Set<String>> and the AlphanumComparator (see here) the compiler says :

The method sortedValuesFromMap(Map<?,Collection<V>>, Comparator<V>) in the type MyUtils is not applicable for the arguments (Map<String,Set<String>, AlphanumComparator)

Turning Collection to Set in the signature of sortedValuesFromMap would fix it – but I do not want to do that. So why is Java forcing me to do so, although Set<E> is implementing Collection<E>?

PS: If someone is interested in my code:

public static <V> List<V> sortedValuesFromMap(Map<?, Collection<V>> keysValues,
        Comparator<V> comp) {
    List<V> values = new LinkedList<V>();
    for (Collection<V> col : keysValues.values()) {
        values.addAll(col);
    }
    Collections.sort(values, comp);
    return values;
}
Anders
  • 8,307
  • 9
  • 56
  • 88
user3389669
  • 799
  • 6
  • 20

2 Answers2

3

Just as a List<Dog> is not a List<Animal>, a Map<String, Set<String>> is not a Map<String, Collection<String>> and it's not a Map<?, Collection<String>>.

The solution here is to add a wildcard in place of Set to allow a subclass in the generic type parameter.

//                                                   Add v
public static <V> List<V> sortedValuesFromMap(Map<?, ? extends Collection<V>> keysValues,
    Comparator<V> comp) {
Community
  • 1
  • 1
rgettman
  • 176,041
  • 30
  • 275
  • 357
0

Your problem is that Map<String,Set<V>> is not a subtype of Map<String,Collection<V>>. Think about what type x can be, if it's legal to write x.put("Hello",new ArrayList<V>());

In this case, x could be a Map<String,Collection<V>>, since an ArrayList<V> is certainly a Collection<V>. But it couldn't be a Map<String,Set<V>>, since an ArrayList<V> is not a Set<V>. Therefore it's untrue to say that any Map<String,Set<V>> "is a" Map<String,Collection<V>>.

The type that you want is either Map<String,? extends Collection<V>> or Map<?,? extends Collection<V>>. Both Map<String,Set<V>> and Map<String,Collection<V>> are subtypes of these types.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110