简体   繁体   English

如何有效地遍历 Java Map 中的每个条目?

[英]How do I efficiently iterate over each entry in a Java Map?

If I have an object implementing the Map interface in Java and I wish to iterate over every pair contained within it, what is the most efficient way of going through the map?如果我有一个 object 在 Java 中实现Map接口,并且我希望遍历其中包含的每一对,那么通过 map 的最有效方法是什么?

Will the ordering of elements depend on the specific map implementation that I have for the interface?元素的顺序是否取决于我对接口的特定 map 实现?

Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

On Java 10+:在 Java 10+ 上:

for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

To summarize the other answers and combine them with what I know, I found 10 main ways to do this (see below).为了总结其他答案并将它们与我所知道的结合起来,我找到了 10 种主​​要方法来做到这一点(见下文)。 Also, I wrote some performance tests (see results below).另外,我写了一些性能测试(见下面的结果)。 For example, if we want to find the sum of all of the keys and values of a map, we can write:例如,如果我们想找到一个映射的所有键和值的总和,我们可以这样写:

  1. Using iterator and Map.Entry使用迭代器Map.Entry

     long i = 0; Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> pair = it.next(); i += pair.getKey() + pair.getValue(); }
  2. Using foreach and Map.Entry使用foreachMap.Entry

     long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }
  3. Using forEach from Java 8在 Java 8 中使用forEach

     final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v);
  4. Using keySet and foreach使用keySetforeach

     long i = 0; for (Integer key : map.keySet()) { i += key + map.get(key); }
  5. Using keySet and iterator使用keySet迭代器

    long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); }
  6. Using for and Map.Entry使用forMap.Entry

     long i = 0; for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<Integer, Integer> entry = entries.next(); i += entry.getKey() + entry.getValue(); }
  7. Using the Java 8 Stream API使用 Java 8 Stream API

     final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Using the Java 8 Stream API parallel并行使用 Java 8 Stream API

     final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
  9. Using IterableMap of Apache Collections使用Apache Collections IterableMap

     long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }
  10. Using MutableMap of Eclipse (CS) collections使用 Eclipse (CS) 集合的MutableMap

     final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });

Perfomance tests (mode = AverageTime, system = Windows 8.1 64-bit, Intel i7-4790 3.60 GHz, 16 GB)性能测试(模式 = AverageTime,系统 = Windows 8.1 64 位,Intel i7-4790 3.60 GHz,16 GB)

  1. For a small map (100 elements), score 0.308 is the best对于小地图(100 个元素),得分 0.308 是最好的

    Benchmark Mode Cnt Score Error Units test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 µs/op test10_UsingEclipseMap avgt 10 0.309 ± 0.009 µs/op test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 µs/op test6_UsingForAndIterator avgt 10 0.387 ± 0.016 µs/op test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 µs/op test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 µs/op test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 µs/op test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 µs/op test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 µs/op test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 µs/op
  2. For a map with 10000 elements, score 37.606 is the best对于包含 10000 个元素的地图,得分 37.606 是最好的

    Benchmark Mode Cnt Score Error Units test10_UsingEclipseMap avgt 10 37.606 ± 0.790 µs/op test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 µs/op test6_UsingForAndIterator avgt 10 50.332 ± 0.507 µs/op test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 µs/op test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 µs/op test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 µs/op test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 µs/op test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 µs/op test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 µs/op test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 µs/op
  3. For a map with 100000 elements, score 1184.767 is the best对于包含 100000 个元素的地图,得分 1184.767 是最好的

    Benchmark Mode Cnt Score Error Units test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 µs/op test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 µs/op test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 µs/op test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 µs/op test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 µs/op test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 µs/op test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 µs/op test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 µs/op test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 µs/op test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 µs/op

Graphs (performance tests depending on map size)图表(性能测试取决于地图大小)

在此处输入图片说明

Table (perfomance tests depending on map size)表(性能测试取决于地图大小)

          100     600      1100     1600     2100
test10    0.333    1.631    2.752    5.937    8.024
test3     0.309    1.971    4.147    8.147   10.473
test6     0.372    2.190    4.470    8.322   10.531
test1     0.405    2.237    4.616    8.645   10.707
test2     0.376    2.267    4.809    8.403   10.910
test7     0.473    2.448    5.668    9.790   12.125
test9     0.565    2.830    5.952   13.220   16.965
test4     0.808    5.012    8.813   13.939   17.407
test5     0.810    5.104    8.533   14.064   17.422
test8     5.173   12.499   17.351   24.671   30.403

All tests are on GitHub .所有测试都在GitHub 上

In Java 8 you can do it clean and fast using the new lambdas features:在 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));

The type of k and v will be inferred by the compiler and there is no need to use Map.Entry anymore. kv的类型将由编译器推断,不再需要使用Map.Entry

Easy-peasy!十分简单!

Yes, the order depends on the specific Map implementation.是的,顺序取决于特定的 Map 实现。

@ScArcher2 has the more elegant Java 1.5 syntax . @ScArcher2 具有更优雅的 Java 1.5 语法 In 1.4, I would do something like this:在 1.4 中,我会做这样的事情:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

Typical code for iterating over a map is:迭代地图的典型代码是:

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

HashMap is the canonical map implementation and doesn't make guarantees (or though it should not change the order if no mutating operations are performed on it). HashMap是规范的映射实现并且不做任何保证(或者如果没有对其执行变异操作,它不应该更改顺序)。 SortedMap will return entries based on the natural ordering of the keys, or a Comparator , if provided. SortedMap将返回基于键的自然顺序,或者一个条目Comparator ,如果提供。 LinkedHashMap will either return entries in insertion-order or access-order depending upon how it has been constructed. LinkedHashMap将根据它的构造方式以插入顺序或访问顺序返回条目。 EnumMap returns entries in the natural order of keys. EnumMap以键的自然顺序返回条目。

(Update: I think this is no longer true. ) Note, IdentityHashMap entrySet iterator currently has a peculiar implementation which returns the same Map.Entry instance for every item in the entrySet ! (更新:我认为这不再正确。 )注意, IdentityHashMap entrySet迭代器目前有一个特殊的实现,它为entrySet每个项目返回相同的Map.Entry实例! However, every time a new iterator advances the Map.Entry is updated.但是,每次新迭代器前进时,都会更新Map.Entry

Example of using iterator and generics:使用迭代器和泛型的例子:

Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Map.Entry<String, String> entry = entries.next();
  String key = entry.getKey();
  String value = entry.getValue();
  // ...
}

This is a two part question:这是一个两部分的问题:

How to iterate over the entries of a Map - @ScArcher2 has answered that perfectly.如何迭代 Map 的条目- @ScArcher2 已经完美地回答了这个问题。

What is the order of iteration - if you are just using Map , then strictly speaking, there are no ordering guarantees .迭代的顺序是什么- 如果您只是使用Map ,那么严格来说,没有排序保证 So you shouldn't really rely on the ordering given by any implementation.所以你不应该真正依赖任何实现给出的顺序。 However, the SortedMap interface extends Map and provides exactly what you are looking for - implementations will aways give a consistent sort order.但是, SortedMap接口扩展了Map并提供了您正在寻找的内容 - 实现将提供一致的排序顺序。

NavigableMap is another useful extension - this is a SortedMap with additional methods for finding entries by their ordered position in the key set. NavigableMap是另一个有用的扩展- 这是一个SortedMap带有附加方法,用于按条目在键集中的有序位置查找条目。 So potentially this can remove the need for iterating in the first place - you might be able to find the specific entry you are after using the higherEntry , lowerEntry , ceilingEntry , or floorEntry methods.因此,这可能首先可以消除迭代的需要 - 在使用higherEntrylowerEntryceilingEntryfloorEntry方法后,您可能能够找到您所在的特定entry The descendingMap method even gives you an explicit method of reversing the traversal order . descendingMap方法甚至为您提供了一种反转遍历顺序的显式方法。

There are several ways to iterate over map.有几种方法可以迭代地图。

Here is comparison of their performances for a common data set stored in map by storing a million key value pairs in map and will iterate over map.这是通过在 map 中存储一百万个键值对并将迭代 map 中存储在 map 中的常见数据集的性能比较。

1) Using entrySet() in for each loop 1) 在每个循环中使用entrySet()

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 milliseconds 50 毫秒

2) Using keySet() in for each loop 2) 在每个循环中使用keySet()

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 milliseconds 76 毫秒

3) Using entrySet() and iterator 3) 使用entrySet()和迭代器

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 milliseconds 50 毫秒

4) Using keySet() and iterator 4) 使用keySet()和迭代器

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 milliseconds 75 毫秒

I have referred this link .我已经提到了this link

仅供参考,如果您只对地图的键/值感兴趣,而不对其他键/值感兴趣,您也可以使用map.keySet()map.values()

The correct way to do this is to use the accepted answer as it is the most efficient.正确的方法是使用公认的答案,因为它是最有效的。 I find the following code looks a bit cleaner.我发现以下代码看起来更简洁。

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

使用Java 8 ,您可以使用 forEach 和 lambda 表达式迭代 Map,

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

With Eclipse Collections , you would use the forEachKeyValue method on the MapIterable interface, which is inherited by the MutableMap and ImmutableMap interfaces and their implementations.对于Eclipse Collections ,您将在MapIterable接口上使用forEachKeyValue方法,该方法由MutableMapImmutableMap接口及其实现继承。

MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Using an anonymous inner class, you can write the code as follows:使用匿名内部类,您可以编写如下代码:

final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
    public void value(Integer key, String value)
    {
        result.add(key + value);
    }
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Note: I am a committer for Eclipse Collections.注意:我是 Eclipse Collections 的提交者。

In theory, the most efficient way will depend on which implementation of Map.理论上,最有效的方式将取决于 Map 的实现。 The official way to do this is to call map.entrySet() , which returns a set of Map.Entry , each of which contains a key and a value ( entry.getKey() and entry.getValue() ).官方的做法是调用map.entrySet() ,它返回一组Map.Entry ,每个Map.Entry包含一个键和一个值( entry.getKey()entry.getValue() )。

In an idiosyncratic implementation, it might make some difference whether you use map.keySet() , map.entrySet() or something else.在特殊的实现中,使用map.keySet()map.entrySet()或其他方法可能会有所不同。 But I can't think of a reason why anyone would write it like that.但我想不出为什么有人会这样写。 Most likely it makes no difference to performance what you do.很可能它对您所做的性能没有影响。

And yes, the order will depend on the implementation - as well as (possibly) the order of insertion and other hard-to-control factors.是的,顺序将取决于实现 - 以及(可能)插入顺序和其他难以控制的因素。

[edit] I wrote valueSet() originally but of course entrySet() is actually the answer. [编辑] 我最初写的是valueSet()但当然entrySet()实际上是答案。

Java 8爪哇 8

We have got forEach method that accepts a lambda expression .我们有接受lambda 表达式的forEach方法。 We have also got stream APIs.我们也有API。 Consider a map:考虑一张地图:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

Iterate over keys:迭代键:

sample.keySet().forEach((k) -> System.out.println(k));

Iterate over values:迭代值:

sample.values().forEach((v) -> System.out.println(v));

Iterate over entries (Using forEach and Streams):迭代条目(使用 forEach 和 Streams):

sample.forEach((k,v) -> System.out.println(k + ":" + v)); 
sample.entrySet().stream().forEach((entry) -> {
            Object currentKey = entry.getKey();
            Object currentValue = entry.getValue();
            System.out.println(currentKey + ":" + currentValue);
        });

The advantage with streams is they can be parallelized easily in case we want to.流的优点是它们可以很容易地并行化,以防万一。 We simply need to use parallelStream() in place of stream() above.我们只需要使用parallelStream()代替上面的stream()

forEachOrdered vs forEach with streams ? forEachOrdered与带有流的forEach The forEach does not follow encounter order (if defined) and is inherently non-deterministic in nature where as the forEachOrdered does. forEach不遵循遭遇顺序(如果已定义)并且本质上是非确定性的,而forEachOrdered则如此。 So forEach does not guarantee that the order would be kept.所以forEach不保证订单会被保留。 Also check this for more.还要检查这个以获取更多信息。

Lambda Expression Java 8 Lambda表达式 Java 8

In Java 1.8 (Java 8) this has become lot easier by using forEach method from Aggregate operations( Stream operations ) that looks similar to iterators from Iterable Interface.在Java 1.8(Java 8)这已经成为使用从聚合操作的forEach方法(Stream操作)容易得多,类似从Iterable接口迭代器的外观。

Just copy paste below statement to your code and rename the HashMap variable from hm to your HashMap variable to print out key-value pair.只需将下面的语句复制粘贴到您的代码中,并将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.

Below is the sample code that I tried using Lambda Expression .下面是我尝试使用Lambda Expression的示例代码。 This stuff is so cool.这东西太酷了。 Must try.一定要试。

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

Also one can use Spliterator for the same.同样可以使用Spliterator

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

UPDATE更新


Including documentation links to Oracle Docs.包括指向 Oracle Docs 的文档链接。 For more on Lambda go to this link and must read Aggregate Operations and for Spliterator go to this link .有关Lambda 的更多信息,请转到此链接,并且必须阅读聚合操作,对于 Spliterator,请转到此链接

Java 8:爪哇 8:

You can use lambda expressions:您可以使用 lambda 表达式:

myMap.entrySet().stream().forEach((entry) -> {
    Object currentKey = entry.getKey();
    Object currentValue = entry.getValue();
});

For more information, follow this .有关更多信息,请按照

In Map one can Iteration over keys and/or values and/or both (eg, entrySet) depends on one's interested in_ Like:在 Map 中,可以对keys和/或values和/或both (eg, entrySet)进行迭代, both (eg, entrySet)取决于一个人的兴趣_喜欢:

  1. Iterate through the keys -> keySet() of the map:遍历映射的keys -> keySet()

     Map<String, Object> map = ...; for (String key : map.keySet()) { //your Business logic... }
  2. Iterate through the values -> values() of the map:遍历地图的values -> values()

     for (Object value : map.values()) { //your Business logic... }
  3. Iterate through the both -> entrySet() of the map:遍历地图的both -> entrySet()

     for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); //your Business logic... }

Moreover, there are 3 different ways to iterate through a HashMap.此外,有 3 种不同的方式来遍历 HashMap。 They are as below:它们如下:

//1.
for (Map.Entry entry : hm.entrySet()) {
    System.out.print("key,val: ");
    System.out.println(entry.getKey() + "," + entry.getValue());
}

//2.
Iterator iter = hm.keySet().iterator();
while(iter.hasNext()) {
    Integer key = (Integer)iter.next();
    String val = (String)hm.get(key);
    System.out.println("key,val: " + key + "," + val);
}

//3.
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry entry = (Map.Entry) it.next();
    Integer key = (Integer)entry.getKey();
    String val = (String)entry.getValue();
    System.out.println("key,val: " + key + "," + val);
}

Try this with Java 1.4:用 Java 1.4 试试这个:

for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){

  Entry entry = (Entry) entries.next();

  System.out.println(entry.getKey() + "/" + entry.getValue());

  //...
}

The ordering will always depend on the specific map implementation.排序将始终取决于特定的地图实现。 Using Java 8 you can use either of these:使用 Java 8,您可以使用以下任一方式:

map.forEach((k,v) -> { System.out.println(k + ":" + v); });

Or:或者:

map.entrySet().forEach((e) -> {
            System.out.println(e.getKey() + " : " + e.getValue());
        });

The result will be the same (same order).结果将是相同的(相同的顺序)。 The entrySet backed by the map so you are getting the same order.由地图支持的 entrySet,因此您将获得相同的订单。 The second one is handy as it allows you to use lambdas, eg if you want only to print only Integer objects that are greater than 5:第二个很方便,因为它允许您使用 lambdas,例如,如果您只想打印大于 5 的 Integer 对象:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

The code below shows iteration through LinkedHashMap and normal HashMap (example).下面的代码显示了通过 LinkedHashMap 和普通 HashMap 的迭代(示例)。 You will see difference in the order:您会看到顺序上的差异:

public class HMIteration {


    public static void main(String[] args) {
        Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
        Map<Object, Object> hashMap = new HashMap<>();

        for (int i=10; i>=0; i--) {
            linkedHashMap.put(i, i);
            hashMap.put(i, i);
        }

        System.out.println("LinkedHashMap (1): ");
        linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nLinkedHashMap (2): ");

        linkedHashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });


        System.out.println("\n\nHashMap (1): ");
        hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nHashMap (2): ");

        hashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });
    }
}

Output:输出:

LinkedHashMap (1):
10 (#=10):10, 9 (#=9):9, 8 (#=8):8, 7 (#=7):7, 6 (#=6):6, 5 (#=5):5, 4 (#=4):4, 3 (#=3):3, 2 (#=2):2, 1 (#=1):1, 0 (#=0):0,
LinkedHashMap (2):
10 : 10, 9 : 9, 8 : 8, 7 : 7, 6 : 6, 5 : 5, 4 : 4, 3 : 3, 2 : 2, 1 : 1, 0 : 0,
HashMap (1):
0 (#:0):0, 1 (#:1):1, 2 (#:2):2, 3 (#:3):3, 4 (#:4):4, 5 (#:5):5, 6 (#:6):6, 7 (#:7):7, 8 (#:8):8, 9 (#:9):9, 10 (#:10):10,
HashMap (2):
0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10,

最紧凑的 Java 8:

map.entrySet().forEach(System.out::println);

If I have an object implementing the Map interface in Java and I wish to iterate over every pair contained within it, what is the most efficient way of going through the map?如果我有一个在 Java 中实现 Map 接口的对象,并且我希望迭代其中包含的每一对,那么遍历地图的最有效方法是什么?

If efficiency of looping the keys is a priority for your app, then choose a Map implementation that maintains the keys in your desired order.如果循环键的效率是您的应用程序的优先事项,则选择一个Map实现,以按您所需的顺序维护键。

Will the ordering of elements depend on the specific map implementation that I have for the interface?元素的顺序是否取决于我对界面的特定地图实现?

Yes, absolutely.是的,一点没错。

  • Some Map implementations promise a certain iteration order, others do not.一些Map实现承诺特定的迭代顺序,而另一些则没有。
  • Different implementations of Map maintain different ordering of the key-value pairs. Map不同实现维护不同的键值对排序。

See this table I created summarizing the various Map implementations bundled with Java 11. Specifically, notice the iteration order column.请参阅我创建的总结与 Java 11 捆绑在一起的各种Map实现的表格。具体来说,请注意迭代顺序列。 Click/tap to zoom.单击/点击可缩放。

Java 11 中的地图实现表,比较它们的特性

You can see there are four Map implementations maintaining an order :您可以看到有四个Map实现维护一个订单

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap interface NavigableMap界面

Two of those implement the NavigableMap interface: TreeMap & ConcurrentSkipListMap .其中两个实现了NavigableMap接口: TreeMapConcurrentSkipListMap

The older SortedMap interface is effectively supplanted by the newer NavigableMap interface.较新的NavigableMap界面有效地取代了较旧的SortedMap界面。 But you may find 3rd-party implementations implementing the older interface only.但是您可能会发现仅实现旧接口的 3rd 方实现。

Natural order自然秩序

If you want a Map that keeps its pairs arranged by the “natural order” of the key, use TreeMap or ConcurrentSkipListMap .如果您想要一个按键的“自然顺序”排列其对的Map ,请使用TreeMapConcurrentSkipListMap The term “natural order” means the class of the keys implements Comparable .术语“自然顺序”意味着键的类实现了Comparable The value returned by the compareTo method is used for comparison in sorting. compareTo方法返回的值用于排序中的比较。

Custom order定制订单

If you want to specify a custom sorting routine for your keys to be used in maintaining a sorted order, pass a Comparator implementation appropriate to the class of your keys.如果要为键指定自定义排序例程以用于维护排序顺序,请传递适合键类的Comparator实现。 Use either TreeMap or ConcurrentSkipListMap , passing your Comparator .使用TreeMapConcurrentSkipListMap ,传递您的Comparator

Original insertion order原始广告订单

If you want the pairs of your map to be kept in their original order in which you inserted them into the map, use LinkedHashMap .如果您希望地图对按将它们插入地图时的原始顺序保留,请使用LinkedHashMap

Enum-definition order枚举定义顺序

If you are using an enum such as DayOfWeek or Month as your keys, use the EnumMap class.如果您使用枚举(例如DayOfWeekMonth作为键,请使用EnumMap类。 Not only is this class highly optimized to use very little memory and run very fast, it maintains your pairs in the order defined by the enum.这个类不仅高度优化以使用很少的内存并且运行速度非常快,它还按照枚举定义的顺序维护您的对。 For DayOfWeek , for example, the key of DayOfWeek.MONDAY will be first found when iterated, and the key of DayOfWeek.SUNDAY will be last.对于DayOfWeek ,例如,关键DayOfWeek.MONDAY将首先被发现时,迭代和关键DayOfWeek.SUNDAY将是最后一次。

Other considerations其他注意事项

In choosing a Map implementation, also consider:在选择Map实现时,还要考虑:

  • NULLs. NULL。 Some implementations forbid/accept a NULL as key and/or value.一些实现禁止/接受 NULL 作为键和/或值。
  • Concurrency.并发。 If you are manipulating the map across threads, you must use an implementation that supports concurrency.如果要跨线程操作映射,则必须使用支持并发的实现。 Or wrap the map with Collections::synchronizedMap (less preferable).或者用Collections::synchronizedMap包装地图(不太可取)。

Both of these considerations are covered in the graphic table above.上面的图表中涵盖了这两个考虑因素。

If you have a generic untyped Map you can use:如果你有一个通用的无类型地图,你可以使用:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
public class abcd{
    public static void main(String[] args)
    {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Integer key:testMap.keySet()) {
            String value=testMap.get(key);
            System.out.println(value);
        }
    }
}

OR或者

public class abcd {
    public static void main(String[] args)
    {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Entry<Integer, String> entry : testMap.entrySet()) {
            Integer key=entry.getKey();
            String value=entry.getValue();
        }
    }
}
    Iterator iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry element = (Map.Entry)it.next();
        LOGGER.debug("Key: " + element.getKey());
        LOGGER.debug("value: " + element.getValue());    
    }

These are all the possible ways of iterating HashMap.这些是迭代HashMap的所有可能方式。

HashMap<Integer,String> map=new HashMap<Integer,String>();
    map.put(1,"David");  //Adding elements in Map
    map.put(2,"John");
    map.put(4,"Samyuktha");
    map.put(3,"jasmin");
    System.out.println("Iterating Hashmap...");

    //way 1 (java 8 Method)
    map.forEach((key, value) -> {
        System.out.println(key+" : "+ value);
    });

    //way 2 (java 7 Method)
    for(Map.Entry me : map.entrySet()){
        System.out.println(me.getKey()+" "+me.getValue());
    }

    //way 3 (Legacy way to iterate HashMap)
    Iterator iterator = map.entrySet().iterator();//map.keySet().iterator()
    while (iterator.hasNext())
    {
        Map.Entry me =(Map.Entry)iterator.next();
        System.out.println(me.getKey()+" : "+ me.getValue());
    }
    
}

You can do it using generics:您可以使用泛型来做到这一点:

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());
}

使用 Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

An effective iterative solution over a Map is a for loop from Java 5 through Java 7. Here it is:一个有效的 Map 迭代解决方案是从 Java 5 到 Java 7 的for循环。这里是:

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

From Java 8 you can use a lambda expression to iterate over a Map.从 Java 8 开始,您可以使用 lambda 表达式来迭代 Map。 It is an enhanced forEach它是一个增强的forEach

phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));

If you want to write a conditional for lambda you can write it like this:如果你想为 lambda 写一个条件,你可以这样写:

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});
           //Functional Oprations
            Map<String, String> mapString = new HashMap<>();
            mapString.entrySet().stream().map((entry) -> {
                String mapKey = entry.getKey();
                return entry;
            }).forEach((entry) -> {
                String mapValue = entry.getValue();
            });

            //Intrator
            Map<String, String> mapString = new HashMap<>();
            for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = it.next();
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();
            }

            //Simple for loop
            Map<String, String> mapString = new HashMap<>();
            for (Map.Entry<String, String> entry : mapString.entrySet()) {
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();

            }

Iterating a Map is very easy.迭代Map非常容易。

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

For instance, you have a Map<String, int> data;例如,您有一个Map<String, int> data;

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

There are a lot of ways to do this.有很多方法可以做到这一点。 Below is a few simple steps:下面是几个简单的步骤:

Suppose you have one Map like:假设您有一张地图,例如:

Map<String, Integer> m = new HashMap<String, Integer>();

Then you can do something like the below to iterate over map elements.然后,您可以执行以下操作来迭代地图元素。

// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
    Entry<String, Integer> pair = me.next();
    System.out.println(pair.getKey() + ":" + pair.getValue());
}

// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
    System.out.println(me.getKey() + " : " + me.getValue());
}

// *********** Using keySet *****************************
for(String s : m.keySet()){
    System.out.println(s + " : " + m.get(s));
}

// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
    String key = me.next();
    System.out.println(key + " : " + m.get(key));
}

If I have an object implementing the Map interface in Java and I wish to iterate over every pair contained within it, what is the most efficient way of going through the map?如果我有一个用Java实现Map接口的对象,并且希望对其中包含的每一对进行迭代,那么遍历该映射的最有效方法是什么?

Will the ordering of elements depend on the specific map implementation that I have for the interface?元素的顺序是否取决于我对接口的特定映射实现?

Map.forEach

What about simply using Map::forEach where both the key and the value are passed to your BiConsumer ?简单地使用Map::forEach怎么样,键和值都传递给你的BiConsumer

map.forEach((k,v)->{
    System.out.println(k+"->"+v);
});

Here is a generic type-safe method which can be called to dump any given Map .这是一个通用的类型安全方法,可以调用它来转储任何给定的Map

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

public class MapUtils {
    static interface ItemCallback<K, V> {
        void handler(K key, V value, Map<K, V> map);
    }

    public static <K, V> void forEach(Map<K, V> map, ItemCallback<K, V> callback) {
        Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry<K, V> entry = it.next();

            callback.handler(entry.getKey(), entry.getValue(), map);
        }
    }

    public static <K, V> void printMap(Map<K, V> map) {
        forEach(map, new ItemCallback<K, V>() {
            @Override
            public void handler(K key, V value, Map<K, V> map) {
                System.out.println(key + " = " + value);
            }
        });
    }
}

Example例子

Here is an example of its use.这是它的使用示例。 Notice that the type of the Map is inferred by the method.注意Map的类型是由方法推断的。

import java.util.*;

public class MapPrinter {
    public static void main(String[] args) {
        List<Map<?, ?>> maps = new ArrayList<Map<?, ?>>() {
            private static final long serialVersionUID = 1L;
            {
                add(new LinkedHashMap<String, Integer>() {
                    private static final long serialVersionUID = 1L;
                    {
                        put("One", 0);
                        put("Two", 1);
                        put("Three", 3);
                    }
                });

                add(new LinkedHashMap<String, Object>() {
                    private static final long serialVersionUID = 1L;
                    {
                        put("Object", new Object());
                        put("Integer", new Integer(0));
                        put("Double", new Double(0.0));
                    }
                });
            }
        };

        for (Map<?, ?> map : maps) {
            MapUtils.printMap(map);
            System.out.println();
        }
    }
}

Output输出

One = 0
Two = 1
Three = 3

Object = java.lang.Object@15db9742
Integer = 0
Double = 0.0
package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    }
}

Since Java 10, you can use local variable inference (aka "var") to make a lot of the already available answers less bloated.从 Java 10 开始,您可以使用局部变量推理(又名“var”)来减少许多已经可用的答案的臃肿。 For example:例如:

for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}

There are several ways to iterate a map.有几种方法可以迭代地图。 Please refer to the following code.请参考以下代码。

When you iterate a map using iterator Interface you must go with Entry<K,V> or entrySet() .当您使用迭代器接口迭代地图时,您必须使用Entry<K,V>entrySet()

It looks like this:它看起来像这样:

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

    public class IteratMapDemo{

        public static void main(String arg[]){
            Map<String, String> mapOne = new HashMap<String, String>();
            mapOne.put("1", "January");
            mapOne.put("2", "February");
            mapOne.put("3", "March");
            mapOne.put("4", "April");
            mapOne.put("5", "May");
            mapOne.put("6", "June");
            mapOne.put("7", "July");
            mapOne.put("8", "August");
            mapOne.put("9", "September");
            mapOne.put("10", "Octomber");
            mapOne.put("11", "November");
            mapOne.put("12", "December");

            Iterator it = mapOne.entrySet().iterator();
            while(it.hasNext())
            {
                Map.Entry me = (Map.Entry) it.next();
                //System.out.println("Get Key through While loop = " + me.getKey());
            }
            for(Map.Entry<String, String> entry:mapOne.entrySet()){
                //System.out.println(entry.getKey() + "=" + entry.getValue());
            }

            for (Object key : mapOne.keySet()) {
                System.out.println("Key: " + key.toString() + " Value: " +
                                   mapOne.get(key));
            }
        }
    }

If your reason for iterating trough the Map , is to do an operation on the value and write to a resulting Map .如果您遍历Map的原因是对值执行操作并写入结果Map I recommend using the transform -methods in the Google Guava Maps class.我建议使用Google Guava Maps类中的transform -methods。

import com.google.common.collect.Maps;

After you have added the Maps to your imports, you can use Maps.transformValues and Maps.transformEntries on your maps, like this:Maps添加到导入后,您可以在地图上使用Maps.transformValuesMaps.transformEntries ,如下所示:

public void transformMap(){
    Map<String, Integer> map = new HashMap<>();
    map.put("a", 2);
    map.put("b", 4);

    Map<String, Integer> result = Maps.transformValues(map, num -> num * 2);
    result.forEach((key, val) -> print(key, Integer.toString(val)));
    // key=a,value=4
    // key=b,value=8

    Map<String, String> result2 = Maps.transformEntries(map, (key, value) -> value + "[" + key + "]");
    result2.forEach(this::print);
    // key=a,value=2[a]
    // key=b,value=4[b]
}

private void print(String key, String val){
    System.out.println("key=" + key + ",value=" + val);
}

I like to concat a counter, then save the final value of the counter;我喜欢连接一个计数器,然后保存计数器的最终值;

int counter = 0;
HashMap<String, String> m = new HashMap<String, String>();
for(int i = 0;i<items.length;i++)
{
m.put("firstname"+i, items.get(i).getFirstName());
counter = i;
}

m.put("recordCount",String.valueOf(counter));

Then when you want to retrieve:然后当你想检索时:

int recordCount = Integer.parseInf(m.get("recordCount"));
for(int i =0 ;i<recordCount;i++)
{
System.out.println("First Name :" + m.get("firstname"+i));
}

Using Java 7使用 Java 7

Map<String,String> sampleMap = new HashMap<>();
for (sampleMap.Entry<String,String> entry : sampleMap.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();

    /* your Code as per the Business Justification  */

}

Using Java 8使用 Java 8

Map<String,String> sampleMap = new HashMap<>();

sampleMap.forEach((k, v) -> System.out.println("Key is :  " + k + " Value is :  " + v));

Below are the ways to iterate the HashMaps以下是迭代 HashMap 的方法

Java 8 Method: Java 8 方法:

hashMap.forEach((key, value) -> {
    System.out.println("Value of " + key + " is " + value);
});

Java 7 Method: Java 7 方法:

for (Map.Entry entry : hashMap.entrySet()) {
    System.out.println(entry.getKey() + " Value is " + entry.getValue());
}

Please refer below links for more reference about hashmap请参阅以下链接以获取有关 hashmap 的更多参考

https://beginnersbug.com/get-key-and-value-from-hashmap-in-java/ https://beginnersbug.com/get-key-and-value-from-hashmap-in-java/

https://docs.oracle.com/javase/8/docs/api/java/util/Map.htmlhttps://docs.oracle.com/javase/8/docs/api/java/util/Map.html

It doesn't quite answer the OP's question, but might be useful to others who find this page:它不能完全回答 OP 的问题,但可能对找到此页面的其他人有用:

If you only need the values and not the keys, you can do this:如果你只需要值而不是键,你可以这样做:

Map<Ktype, Vtype> myMap = [...];
for (Vtype v: myMap.values()) {
  System.out.println("value: " + v);
}

Ktype , Vtype are pseudocode. Ktype , Vtype是伪代码。

If you want to iterate through the map in the order that the elements were added, use LinkedHashMap as opposed to just Map .如果您想按照添加元素的顺序遍历地图,请使用LinkedHashMap而不是Map

This approach has worked for me in the past:这种方法过去对我有用:

LinkedHashMap<String,Integer> test=new LinkedHashMap();

test.put("foo",69);
test.put("bar",1337);

for(int i=0;i<test.size();i++){
    System.out.println(test.get(test.keySet().toArray()[i]));
}

Output:输出:

69
1337
Map<String, String> map = 
for (Map.Entry<String, String> entry : map.entrySet()) {
    MapKey = entry.getKey() 
    MapValue = entry.getValue();
}

You can search for the key and with the help of the key you can find the associated value of the map as map has unique key , see what happens when key is duplicate here or here .您可以搜索键,并在键的帮助下找到映射的关联值,因为映射具有唯一键,查看此处此处重复键时会发生什么。

Demo map :演示地图:

 Map<String, String> map = new HashMap();
  map.put("name", "Name");
  map.put("age", "23");
  map.put("address", "NP");
  map.put("faculty", "BE");
  map.put("major", "CS");
  map.put("head", "MDK");
 

To get key only, you can use map.keySet();要仅获取密钥,您可以使用map.keySet(); like this :像这样 :

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

To get value only , you can use map.values();要仅获取 value ,您可以使用map.values(); like this:像这样:

      for(String value : map.values()) {
      System.out.println(value);
  }

To get both key and its value you still can use map.keySet();要同时获取键及其值,您仍然可以使用map.keySet(); and get its corresponding value, like this :并获取其相应的值,如下所示:

 //this prints the key value pair
  for (String k : map.keySet()) {
        System.out.println(k + " " + map.get(k) + " ");
    }

map.get(key) gives the value pointed by that key. map.get(key)给出该键指向的值。

I copied the data of a map to another with this code:我使用以下代码将地图数据复制到另一个地图:

HashMap product =(HashMap)shopping_truck.get(i);
HashMap tmp = new HashMap();
for (Iterator it = product.entrySet().iterator(); it.hasNext();) {
    Map.Entry thisEntry = (Map.Entry) it.next();
    tmp.put(thisEntry.getKey(), thisEntry.getValue());
}

This is the easiest way of doing it I believe...我相信这是最简单的方法...

/* For example, this could be a map object */
Map<String, Integer> MAP = new Map<>();

// Do something like put keys/value pairs into the map, etc...
MAP.put("Denver", 35);
MAP.put("Patriots", 14);

/* Then, simply use a for each loop like this to iterate */
for (Object o : MAP.entrySet()) {
    Map.Entry pair = (Map.Entry) o;
    // Do whatever with the pair here (i.e. pair.getKey(), or pair.getValue();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM