如果我有一个用Java实现Map接口的对象,并且我希望对其中包含的每一对进行迭代,那么最有效的方法是什么?

元素的顺序是否取决于我对接口的特定映射实现?


当前回答

Lambda表达式Java 8

在Java1.8(Java8)中,通过使用Aggregate操作(Stream操作)中的forEach方法,这变得更加容易,它看起来类似于Iterable接口中的迭代器。

只需将下面的粘贴语句复制到代码中,并将HashMap变量从hm重命名为HashMap变量,即可打印出键值对。

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
 *     Logic to put the Key,Value pair in your HashMap hm
 */

// Print the key value pair in one line.

hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

// Just copy and paste above line to your code.

下面是我尝试使用Lambda表达式的示例代码。这东西太酷了。必须尝试。

HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    Random rand = new Random(47);
    int i = 0;
    while(i < 5) {
        i++;
        int key = rand.nextInt(20);
        int value = rand.nextInt(50);
        System.out.println("Inserting key: " + key + " Value: " + value);
        Integer imap = hm.put(key, value);
        if( imap == null) {
            System.out.println("Inserted");
        } else {
            System.out.println("Replaced with " + imap);
        }               
    }

    hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

Output:

Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11

同样也可以使用Spliterator。

Spliterator sit = hm.entrySet().spliterator();

更新


包括指向Oracle文档的文档链接。有关Lambda的更多信息,请访问此链接,必须阅读聚合操作,对于Spliterator,请访问该链接。

其他回答

对于Eclipse集合,您将在MapIterable接口上使用forEachKeyValue方法,该方法由MutableMap和ImmutableMap接口及其实现继承。

MutableMap<Integer, String> map = 
    Maps.mutable.of(1, "One", 2, "Two", 3, "Three");

MutableBag<String> result = Bags.mutable.empty();
map.forEachKeyValue((key, value) -> result.add(key + value));

MutableBag<String> expected = Bags.mutable.of("1One", "2Two", "3Three");
Assertions.assertEquals(expected, result);

将forEachKeyValue与EclipseCollections(EC)Map实现一起使用比使用entrySet更有效的原因是因为EC Map实现不存储Map.Entry对象。将entrySet与EC Map实现一起使用会动态生成Map.Entry对象。forEachKeyValue方法能够避免创建Map.Entry对象,因为它可以直接导航Map实现的内部结构。在这种情况下,使用内部迭代器比使用外部迭代器有好处。

注意:我是Eclipse集合的提交人。

在地图上迭代的典型代码是:

Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
    String key = entry.getKey();
    Thing thing = entry.getValue();
    ...
}

HashMap是规范映射实现,不做任何保证(或者,如果不对其执行任何变异操作,则不应更改顺序)。SortedMap将根据键的自然顺序或Comparator(如果提供)返回条目。LinkedHashMap将按照插入顺序或访问顺序返回条目,具体取决于它的构造方式。EnumMap以键的自然顺序返回条目。

(更新:我认为这不再是真的。)注意,IdentityHashMap entrySet迭代器目前有一个特殊的实现,它为entrySet中的每个项返回相同的Map.Entry实例!然而,每次新迭代器推进Map.Entry时都会更新。

迭代地图非常简单。

for(Object key: map.keySet()){
   Object value= map.get(key);
   //Do your stuff
}

例如,您有一个Map<String,int>数据;

for(Object key: data.keySet()){
  int value= data.get(key);
}

在Java 8中,您可以使用新的lambdas功能快速、干净地完成任务:

 Map<String,String> map = new HashMap<>();
 map.put("SomeKey", "SomeValue");
 map.forEach( (k,v) -> [do something with key and value] );

 // such as
 map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));

k和v的类型将由编译器推断,不再需要使用Map.Entry。

小菜一碟

您可以使用泛型:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}