Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Iterator on Entry Set

Tags:

java

generics

static <V> void myMethod(Map<?, V> map)
{
 Iterator<Entry<?, V>> it = map.entrySet().iterator();
}

I'm seeing below compilation error:
Type mismatch: cannot convert from Iterator<Map.Entry<capture#5-of ?,V>> to Iterator<Map.Entry<?,V>>

like image 294
Venkata Raju Avatar asked Nov 10 '12 07:11

Venkata Raju


People also ask

Why do you need iterators in generic collections?

Iterators of the actual List are implemented as inner classes in the List's class. Therefore we can refer to the List's generic type from the inner class. So why iterators are generic? If we call an iterator from the actual List, the next() method will use the Generic type of the List the iterator was called from.

Why do we use entrySet in Java?

entrySet() method in Java is used to create a set out of the same elements contained in the hash map. It basically returns a set view of the hash map or we can create a new set and store the map elements into them.

Can we iterate HashMap?

In Java HashMap, we can iterate through its keys, values, and key/value mappings.

How do I iterate a String object on a map?

Iterating over Map. Entry<K, V>>) of the mappings contained in this map. So we can iterate over key-value pair using getKey() and getValue() methods of Map. Entry<K, V>. This method is most common and should be used if you need both map keys and values in the loop.


1 Answers

Try

Iterator<? extends Entry<?, V>> it = map.entrySet().iterator();

The reason your attempt doesn't work is a bit hard to see, particularly because Iterator<T> does not consume any T (i.e. it doesn't have a method which takes a T as a parameter).

You can't assign an Iterator<Entry<capture#5-of ?,V>> to an Iterator<Entry<?, V>> for the same reason that you can't assign an Iterator<Entry<Integer, String>> to an Iterator<Entry<?, V>>. The capture#5 is just a name used to differentiate the specific ? found in your method's parameter from other distinct wildcard instances. It could just as easily be a concrete type.

The reason this doesn't work is more clear if instead of Iterator you think of a class like List.

List<Entry<Integer, String>> entries = new ArrayList<>();

//this is a compile error, but assume it is possible
List<Entry<?, String>> wildcardEntries = entries; 

//then since this is already possible
wilcardEntries.add(new Entry<String, String>("a", "b"));
Entry<Integer, String> entry1 = entries.get(0);

//this would result in a type error (ClassCastException)
Integer i = entry1.getKey();

By using ? extends Entry<?, V> you're not exposing yourself to this, as you do not claim to know anything about the type of Entry your Iterator can consume, only what it can produce.

Edit

Though Jiman deleted his answer, he had a good point that using the for-each loop is a lot cleaner approach (assuming you're just trying to iterate over the entries) that would avoid this issue entirely. This should work:

for ( Entry<?, V> entry : map.entrySet() ) {
   //...
}
like image 117
Mark Peters Avatar answered Sep 25 '22 16:09

Mark Peters