Reputation: 113
Given such class (part of it)
import java.util.*;
import java.util.stream.Collectors;
public class A {
private Map<String, Set<String>> map = new LinkedHashMap<>();
public Map<String, Collection<String>> getMap() {
return Collections.unmodifiableMap(map);
}
public static <K, V> Map<K, V> sorted(Map<K, V> map, Comparator<Map.Entry<? super K, ? super V>> comparator) {
return map
.entrySet()
.stream()
.sorted(comparator)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
public Map<String, Collection<String>> getSortedMap() {
Comparator<Map.Entry<String, Collection<String>>> cmp =
Map.Entry.comparingByValue(Comparator.comparingInt(Collection::size));
return sorted(getMap(), cmp);
}
}
I am getting an error on compile
error: method sorted in class A cannot be applied to given types;
return sorted(getMap(), cmp);
^
required: Map<K,V>,Comparator<Entry<? super K,? super V>>
found: Map<String,Collection<String>>,Comparator<Entry<String,Collection<String>>>
reason: cannot infer type-variable(s) K,V
(argument mismatch; Comparator<Entry<String,Collection<String>>> cannot be converted to Comparator<Entry<? super K,? super V>>)
where K,V are type-variables:
K extends Object declared in method <K,V>sorted(Map<K,V>,Comparator<Entry<? super K,? super V>>)
V extends Object declared in method <K,V>sorted(Map<K,V>,Comparator<Entry<? super K,? super V>>)
1 error
When I change A.sorted
signature to be invariant over comparator
parameter i.e. <K, V> Map<K, V> sorted(Map<K, V> map, Comparator<Map.Entry<K, V>> comparator)
it compiles without any issues. However, I don't think my code violates any typing relations. Is this a problem with Java's type inference?
I am using OpenJDK 8.
Upvotes: 2
Views: 207
Reputation: 33885
Generics are invariant. If you declare a parameter Comparater<T>
then it expects exactly Comparator<T>
. In this case case you have K
and V
trough the map which makes K = String
and V = Collection<String>
. That would make the second parameter Comparator<Entry<? super String, ? super Collection<String>>>
, and you can not assign a Comparator<Entry<String,Collection<String>>>
to that, since the type argument to the comparator does not exactly match.
You could declare the Comparator
contra-variant instead:
public static <K, V> Map<K, V> sorted(Map<K, V> map,
Comparator<? super Map.Entry<K, V>> comparator) {
...
}
Upvotes: 2