如何在Java中对HashMap进行迭代?Map.entrySet().iterator()示例

281 阅读5分钟

不仅仅是 HashMap,任何Map的实现,包括旧的 Hashtable、 TreeMap、 LinkedHashMap 和相对较新的 ConcurrentHashMap,都是Java程序员经常问到的问题,他们有一定的经验。好吧,当谈到在Java中选择不同的方法来迭代Map 时,你的需求起着重要的作用。例如,如果你只想遍历HashMap的每个条目 ,而不修改 Map,那么使用Java 1.5的foreach循环遍历条目集对我来说似乎是最优雅的解决方案。

原因是,它只需要两行代码,使用 foreach 循环和Generics,通过获取条目集,我们可以同时获得key和value,而不需要在 HashMap 中进一步搜索 。这使得它成为 Java中 循环 HashMap的最快方式 。

另一方面,如果你想在迭代HashMap的同时删除条目,可能只是选择性地删除
一些条目,那么foreach循环就没有帮助了。

尽管 foreach 循环在内部使用Iterator来遍历元素,但它并没有公开Iterator的句柄,这意味着你只能用Map的remove()方法来删除条目。这不是一个理想的方法,特别是如果你不得不删除很多条目,而且是在迭代过程中。

你的迭代器也可能抛出 ConcurrentModificationException
,这
取决于它是故障安全的还是故障快速的迭代器 。例如,ConcurrentHashMap的迭代器 每周都与实际Map保持一致,不会抛出 ConcurrentModificationException。

这就给我们留下了传统的while循环和迭代器组合,用于使用 Map.entrySet()循环HashMap 并删除条目。

在Java中对HashMap进行迭代的最佳方法及示例

下面是在Java中对任何Map类进行迭代的代码示例,如HashtableLinkedHashMap 。虽然我使用了HashMap进行迭代,但你也可以将同样的技术应用于其他Map实现。因为我们只使用java.uti.Map接口的方法 ,所以解决方案可以扩展到Java中的所有类型的Map。

我们将使用Java 1.5 的foreach 循环,并对每个 Map.Entry 对象 进行迭代 ,我们通过调用 Map.entrySet() 方法 获得这些 对象 。记住要使用泛型,以避免类型转换。使用泛型和foreach循环可以得到非常简洁和优雅的代码,如下所示。

for(Map.Entry<Integer, String> entry : map.entrySet()){    
  System.out.printf("Key : %s and Value: %s %n", entry.getKey(),   
    entry.getValue()); 
}

这个代码片段对于迭代HashMap 来说非常方便,但是有一个缺点,就是不能在不发生ConcurrentModificationException的情况下删除条目 。在下一节,我们将看到使用迭代器的代码,它可以帮助你从Map中删除条目。

在Java中从Map中删除条目

对Map进行迭代的一个原因 是从Map中删除选定的键值对。这是一个一般的Map需求,对于任何类型的Map,如 HashMap、 Hashtable、 LinkedHashMap 甚至是相对较新的ConcurrentHashMap 都是 如此 。

当我们使用 foreach 循环时,它在内部被翻译成了Iterator代码,但是如果没有Iterator的显式句柄,我们就不能在Iteration中删除条目。

如果你这样做,你的Iterator可能会抛出 ConcurrentModificationException。为了避免这种情况,我们需要使用显式Iterator 和while循环来进行遍历。 出于性能考虑 ,我们仍将使用 entrySet() ,但我们将使用 Iterator的 remove() 方法来删除Map中的条目。这里是 在Java中 从 HashMap 中删除键值的代码示例 。

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
}

你可以看到,我们使用的是 Iterator的 remove() 方法,而不是 java.util.Map的方法,后者接受一个key对象。 这段代码对 ConcurrentModificationException是安全的 。

HashMap 迭代器示例

顺便说一下,这里有一个完整的代码例子,结合了两种方法在Java中HashMap进行迭代。正如我之前所说,你可以使用相同的代码片段来迭代任何Map类,我们没有使用HashMap的任何特定方法,代码是基于Map接口完成的。

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

/**
 *
 * Best way to iterate over Map in Java, including any implementation like
 * 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.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

你可以看到,在Java中迭代HashMap的方式非常简单、快速和优雅。你可以访问所有的条目,然后你可以提取键和值,而无需通过HashMap的get()方法。

How to Iterate over HashMap in Java? Map.entrySet().iterator() Example

以上就是关于如何在Java中迭代HashMap 的全部内容。我们已经看到了一些遍历每个条目的方法,但是正如我所说,最好的方法是使用foreach 循环和条目集,如果你只需要遍历,而不用修改实际的Map。

对于过滤来说,这是非常优雅的,你需要 根据一些过滤标准, 从实际的 Map创建另一个 Map。

由于 Map.Entry 对象同时持有key和value,它提供了对它们最快的访问,而不是调用 Map.get(key) 方法,这需要在Map中搜索。

相关的Java集合教程和面试问题来自Java67