java collections - keyset() vs entrySet() in map

119,373

Solution 1

Every call to the Iterator.next() moves the iterator to the next element. If you want to use the current element in more than one statement or expression, you have to store it in a local variable. Or even better, why don't you simply use a for-each loop?

for (String key : map.keySet()) {
    System.out.println(key + ":" + map.get(key));
}

Moreover, loop over the entrySet is faster, because you don't query the map twice for each key. Also Map.Entry implementations usually implement the toString() method, so you don't have to print the key-value pair manually.

for (Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry);
}

Solution 2

Every time you call itr2.next() you are getting a distinct value. Not the same value. You should only call this once in the loop.

Iterator<String> itr2 = keys.iterator();
    while(itr2.hasNext()){
        String v = itr2.next();
        System.out.println("Key: "+v+" ,value: "+m.get(v));
    }

Solution 3

Traversal over the large map entrySet() is much better than the keySet(). Check this tutorial how they optimise the traversal over the large object with the help of entrySet() and how it helps for performance tuning.

Solution 4

An Iterator moves forward only, if it read it once, it's done. Your

m.get(itr2.next());

is reading the next value of itr2.next();, that is why you are missing a few (actually not a few, every other) keys.

Share:
119,373
AllTooSir
Author by

AllTooSir

Updated on January 12, 2020

Comments

  • AllTooSir
    AllTooSir over 4 years

    I put a string array elements is a map where elements of string array is key and frequency of word is value, e.g.:

    String[] args = {"if","it","is","to","be","it","is","up","me","to","delegate"};
    

    then the map will have entries like [ if:1, it:2 .... ]

    Set<String> keys = m.keySet();
    System.out.println("keyset of the map : "+keys);
    

    prints all keys: "if","it","is","to","be","it","is","up","me","to","delegate"

    Set<Map.Entry<String, Integer>> entrySet = m.entrySet();
    Iterator<Map.Entry<String, Integer>> i = entrySet.iterator();
    while(i.hasNext()){
        Map.Entry<String, Integer> element = i.next();
        System.out.println("Key: "+element.getKey()+" ,value: "+element.getValue());
    }
    

    prints all key values pairs :

    Using entry set prints all values:

    Key: if ,value: 1
    Key: it ,value: 2
    Key: is ,value: 2
    Key: to ,value: 2
    Key: be ,value: 1
    Key: up ,value: 1
    Key: me ,value: 1
    Key: delegate ,value: 1
    

    But the block of code below should print exactly the same output as above, but it does not:

    Iterator<String> itr2 = keys.iterator();
    while(itr2.hasNext()){
        //System.out.println(itr1.next()+" ");
        //System.out.println(m.get(itr1.next())+" ");
        System.out.println("Key: "+itr2.next()+" ,value: "+m.get(itr2.next()));
    }
    

    It prints:

    Key: if ,value: 2
    Key: is ,value: 2
    Key: be ,value: 1
    Key: me ,value: 1
    

    But if we uncomment line 1 in the while loop i.e

    System.out.println(itr1.next()+" ");
    

    and comment the line

    System.out.println("Key: "+itr2.next()+" ,value: "+m.get(itr2.next()));
    

    Then we get all keys: {"if","it","is","to","be","it","is","up","me","to","delegate"};

    If we use m.get() with itr2.next(), then the iterator does not have few keys!

  • Amir Pashazadeh
    Amir Pashazadeh over 12 years
    In Effective Java book the same bug is mentioned and that's why using foreach loop is the preferred one.
  • Amir Pashazadeh
    Amir Pashazadeh over 12 years
    It was lucky of you to have even number of entries in your map, other wise you would encounter a RuntimeException
  • brady
    brady over 12 years
    Thanks for mentioning this very important point: use the entry set to avoid the unnecessary overhead of the call to get().
  • Mike Yockey
    Mike Yockey over 12 years
    +1 to Amir's comment. Unless you need to remove items from the collection, using the Iterator directly will only introduce the possibility of errors. You should use the foreach looping style for simple read loops.
  • HenryNguyen
    HenryNguyen over 7 years
    "because you don't query the map twice for each key" why twice? I thought you query only once when you do map.get(key) ?
  • Evil Washing Machine
    Evil Washing Machine about 7 years
    @HenryNguyen I believe he meant that you're querying it once when you use the iterator to fetch the key