Why does Map <String, Set <String>> match Map <T, Set <? >>?
I have a method with the following signature:
public <T> int numberOfValues(Map<T, Set<?>> map) However, I cannot call this passing to Map<String, Set<String>> . For example, the following does not compile:
Map<String, Set<String>> map = new HashMap<>(); numberOfValues(map); Error message:
numberOfValues (java.util.Map<java.lang.String,java.util.Set<?>>) in class cannot be applied to (java.util.Map<java.lang.String,java.util.Set<java.lang.String>>) However, if I go to the following, everything will be fine:
public <T, V> int numberOfValues(Map<T, Set<V>> map) However, Im is not at all interested in V , since I just want to know the size of each of the sets.
For completeness, this is the whole method:
public <T, V> int numberOfValues(Map<T, Set<V>> map) { int n = 0; for (T key : map.keySet()) { n += map.get(key).size(); } return n; } What Im knows is that this can also be done like this, but that is not a question :)
public <T> int numberOfValues(Map<?, Set<T>> map) { int n = 0; for (Set<T> value : map.values()) { n += value.size(); } return n; } Update: another way to achieve the same
public <T> int numberOfValues(Map<?, Set<T>> map) { int n = 0; for (Object key : map.keySet()) { n += map.get(key).size(); } return n; } Final update: Thanks to Jornes' answer, this is the final implementation ...
public int numberOfValues(Map<?, ? extends Set<?>> map) { int n = 0; for (Set<?> value : map.values()) { n += value.size(); } return n; } You are missing the fact that Set<?> also used as a generic parameter. And generics are invariant. that is, when the Map<String, Set<?>> parameter, the argument passed must be exactly Map<String, Set<?> (or a subtype). If using Set<V> type argument is output.
You can solve this problem with a limited template:
public <T> int numberOfValues(Map<T, ? extends Set<?>> map) { ... } Hint:
In your method numberOfValues it is completely legal to write something like
Set<Object> set = new HashSet<>(); set.add(1); set.add("Powned"); map.put(null, set); You can replace null with a suitable key already on the map to make a valid display, completely violating the type safety in the surrounding code.
Either output or explicitly define the type of set, or add a wildcard binding to prevent access to map mutations (e.g. ? extends Set<?> )