Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type mismatch when using Map.entrySet()

I have the following situation: In the code below, the method foo compiles while the method bar won't. At the method call entrySet (indicated in the code) the compiler says:

Type mismatch: cannot convert 
from Set<Map.Entry<capture#1-of ? extends K,capture#2-of ? extends V>> 
to Set<Map.Entry<? extends K,? extends V>>

Interestingly, the quickfix of Eclipse proposes to

Change type of 's' to Set<Entry<? extends K, ? extends V>>

which only changes the code because the quickfix is ignoring its own proposal and changing the type of s to Set<?> instead.

I am using JDK1.8.0_51 and Eclipse 4.4.0. Maybe it has something to do with the wildcards or captures? Any help or advice would be appreciated. Thanks in advance!

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class MyClass<K, V> {
    public void foo(Set<Entry<? extends K, ? extends V>> set) {
        Iterator<Entry<? extends K, ? extends V>> i = set.iterator();
    }

    public void bar(Map<? extends K, ? extends V> map) {
        Set<Entry<? extends K, ? extends V>> s = map.entrySet();
                                                 ^^^^^^^^^^^^^^
    }
}
like image 941
Marcus Avatar asked Mar 15 '23 00:03

Marcus


2 Answers

Imagine K and V are Number. The declaration does not link the types passed in with the map to those used in the entry set. Although we know it could never happen, if map is a Map<Integer,Integer> then the declaration allows s to be a Set<Entry<Double,Double>> as that still extends Number.

Therefore, if you are explicit that these types match, by writing this:

public <K0 extends K, V0 extends V> void bar(Map<K0,V0> map) {
    Set<Entry<K0,V0>> s = map.entrySet();
}

Your meaning is explicit, that the type of 's' will match exactly the types for 'map'. Hence it compiles happily.

like image 67
Simon G. Avatar answered Mar 17 '23 14:03

Simon G.


The short answer is that, if you declared the Set in the way you have in your question, it would be possible to add entries to it which did not conform to the types of the objects passed in to the method. Java does not retain sufficient information to check that the "? extends K" in the Set definition is the same as the "? extends K" in the method parameter.

To avoid this Java requires you to declare the assignment as:

Set<? extends Map.Entry<? extends K,? extends V>> s = map.entrySet();

... and you will find you cannot add your own entries into this set - at least, not without doing a lot of bad casting which will generate a lot of warnings.

As someone mentioned above, this question covers the subject in more detail: Generic Iterator on Entry Set

like image 28
BarrySW19 Avatar answered Mar 17 '23 13:03

BarrySW19