Tuesday, August 13, 2013

Best way to Iterate over each Entry in HashMap in Java | How to loop Map to remove Entries

What is the best way to Iterate over HashMap in Java? and not just HashMap, but any Map implementation including old Hashtable, TreeMap, LinkedHashMap and relatively newer ConcurrentHashMap, is a frequently asked queries from Java Programmers, with some experience under his belt. Well, when it comes to choosing between different ways to iterate over Map in Java, it's you need, which plays an important role. For example, if you just want to iterate over each entry of HashMap, without modifying Map, then iterating over entry set using Java 1.5 foreach loop seems most elegant solution to me. Reason, it just two lines of code using foreach loop and Generics, and by getting set of entries, we get key and value together, without further searching in HashMap. This makes it also fastest way to loop over HashMap in Java. On the other hand, if you want to remove entries, while iterating over HashMap, may be only selective entries, than foreach loop will not help. Though foreach loop internally uses Iterator for traversing elements, It doesn't expose handle to that Iterator, which means you only have remove() method of Map to remove entries. That's not the ideal way, especially if you had to remove lot of entries and that to during Iteration. Your Iterator may also throw ConcurrentModificationException, depending upon it's fail-safe or fail-fast Iterator. E.g. Iterator of ConcurrentHashMap are weekly consistent with actual Map and doesn't throw ConcurrentModificationException. This leaves us with traditional while loop and Iterator combo, for looping HashMap using Map.entrySet() and removing entries.


Best way to Iterate over HashMap in Java

Here is the code example of Iterating over any Map class in Java e.g. Hashtable or LinkedHashMap. Though I have used HashMap for iteration purpose, you can apply same technique to other Map implementations. Since we are only using methods from java.uti.Map interface, solution is extensible to all kinds of Map in Java. We will use Java 1.5 foreach loop and Iterating over each Map.Entry object, which we get by calling Map.entrySet() method. Remember to use Generics, to avoid type casting. Use of Generics and foreach loop result in very concise and elegant code, as shown below.


for(Map.Entry<Integer, String> entry : map.entrySet()){
    System.out.printf("Key : %s and Value: %s %n", entry.getKey(), entry.getValue());
}
 
This code snippet is very handy for iterating HashMap, but has just one drawback, you can not remove entries without risking ConcurrentModificationException. In next section, we will see code using Iterator, which can help you for removal of entries from Map.

Removing Entries from Map in Java

One reason for iterating over Map is removing selected key value pairs from Map. This is a general Map requirement and holds true for any kind of Map e.g. HashMap, Hashtable, LinkedHashMap or even relatively new ConcurrentHashMap. When we use foreach loop, it internally translated into Iterator code, but without explicit handle to Iterator, we just can not remove entries during Iteration. If you do,  your Iterator may throw ConcurrentModificationException. To avoid this, we need to use explicit Iterator and while loop for traversal. We will still use entrySet() for performance reason, but we will use Iterator's remove() method for deleting entries from Map. Here code example  to remove key values from HashMap in Java:

Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
   Map.Entry<Integer, String> entry = iterator.next();
   System.out.printf("Key : %s and Value: %s %n", entry.getKey(), entry.getValue());
   iterator.remove(); // right way to remove entries from Map, 
                      // avoids ConcurrentModificationException
}

You can see, we are using remove() method from Iterator and not from java.util.Map, which accepts a key object. This code is safe from ConcurrentModificationException.

HashMap Iterator Example

By the way, here is complete code example, combining both approaches for iterating over HashMap in Java. As I said before, you can use same code snippet to iterate any Map class, we are not using any specific methods from HashMap, code is complete based on Map interface.

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 *
 * Best way to iterate over Map in Java, including any implementation e.g.
 * HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap and Hashtable.
 * Java 1.5 foreach loop is most elegant and combined with entry set also
 * gives best performance, but not suitable for removing entries, as you don't have
 * reference to internal Iterator.
 *
 * Only way to remove entries from Map without throwing ConcurrentModificationException
 * is to use Iterator and while loop.
 *
 * @author http://java67.blogspot.com
 */
public class HashMapIteratorExample {

    public static void main(String args[]) {
     
        // Initializing HashMap with some key values
        Map<Integer, String> map = new HashMap<Integer, String>();
        map.put(1, "Core Java");
        map.put(2, "Java SE");
        map.put(3, "Java ME");
        map.put(4, "Java EE");
        map.put(5, "Java FX");
       
        // Iterate over HashMap using foreach loop
        System.out.println("Java 1.5 foreach loop provides most elegant
                             way to iterate over HashMap in Java");
        for(Map.Entry<Integer, String> entry : map.entrySet()){
            System.out.printf("Key : %s and Value: %s %n", entry.getKey(),
                                                           entry.getValue());
        }
       
        // Better way to loop over HashMap, if you want to remove entry
        System.out.println("Use Iterator and while loop, if you want 
                              to remove entries from HashMap during iteration");
        Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer, String> entry = iterator.next();
            System.out.printf("Key : %s and Value: %s %n", entry.getKey(), 
                                                           entry.getValue());
            iterator.remove(); // right way to remove entries from Map, 
                               // avoids ConcurrentModificationException
        }
    }    
  
}

Output:
Java 1.5 foreach loop provides most elegant way to iterate over HashMap in Java
Key : 1 and Value: Core Java
Key : 2 and Value: Java SE
Key : 3 and Value: Java ME
Key : 4 and Value: Java EE
Key : 5 and Value: Java FX
Use Iterator and while loop, if you want to remove entries from HashMap during iteration
Key : 1 and Value: Core Java
Key : 2 and Value: Java SE
Key : 3 and Value: Java ME
Key : 4 and Value: Java EE
Key : 5 and Value: Java FX

That's all about How to Iterator over HashMap in Java. We have seen couple of ways to iterate over each entry, but as I said, best way is to use foreach loop and entry set, if you just need to traverse, without modifying actual Map. It's very elegant for filtering, where you need to create another Map, from actual Map, based on some filtering criterion. Since Map.Entry object holds both key and value, it provides fastest access to them, instead of calling Map.get(key) method, which involves searching in Map.

Related Java Collection Tutorials and Interview Questions from Java67

2 comments:

  1. In my opinion best way to iterate a Map is by using it's keySet() instead of entrySet() because you often need keys to perform filtering or any kind of processing logic, and only require value on need basis. By using entrySet(), your Set will require more memory as they now hold both key and value.

    ReplyDelete
  2. Do you know twitter is also part of JCP and OpenJDK process , see here

    ReplyDelete

Java67 Headline Animator