traverse 如何有效地迭代Java Map中的每個條目?




map traverse java (24)

使用迭代器和泛型的示例:

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

如果我有一個用Java實現Map接口的對象,並希望迭代其中包含的每一對,那麼通過地圖的最有效方法是什麼?

元素的排序是否取決於我對界面的具體映射實現?


僅供參考,如果您只對地圖的鍵/值感興趣而不感興趣,則還可以使用map.keySet()map.values()


使用Eclipse Collections (以前稱為GS Collections ),您可以在MapIterable接口上使用forEachKeyValue方法,該方法由MutableMap和ImmutableMap接口及其實現繼承。

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

使用Java 8 lambda語法,您可以按如下方式編寫代碼:

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

注意:我是Eclipse Collections的提交者。


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

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

最好的方法是entrySet()


在Map中,可以對keys和/或values和/或both (eg, entrySet)進行迭代both (eg, entrySet)取決於一個人的興趣_喜歡:

1.)遍歷地圖的keys -> keySet()

Map<String, Object> map = ...;

for (String key : map.keySet()) {
    //your Business logic...
}

2.)迭代地圖的values -> values()

for (Object value : map.values()) {
    //your Business logic...
}

3.)遍歷地圖的both -> entrySet()

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

此外,通過HashMap迭代有3種不同的方法。 它們如下 _

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

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

使用Java 8

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

在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));

kv的類型將由編譯器推斷,不再需要使用Map.Entry

十分簡單!


是的,訂單取決於具體的Map實施。

@ ScArcher2具有更優雅的Java 1.5語法 。 在1.4中,我會做這樣的事情:

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

在Java 8中,我們有forEach方法接受link 。 我們還有stream API。 考慮一張地圖:

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

迭代鍵:

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

迭代值:

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

迭代條目(使用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);
        });

流的優點是它們可以在我們想要的情況下輕鬆並行化。 我們只需要使用parallelStream()代替上面的stream()


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

有很多方法可以做到這一點。 以下是幾個簡單的步驟:

假設您有一個地圖,如:

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

然後你可以做類似下面的事情迭代地圖元素。

// ********** 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));
}

如果您有一個通用的無類型地圖,您可以使用:

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

你可以使用泛型來做到這一點:

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

這是一個兩部分問題:

如何迭代Map的條目 - @ ScArcher2已經完美地answered這個問題。

迭代的順序是什麼 - 如果你只是使用Map ,那麼嚴格來說, 沒有排序保證 。 所以你不應該真正依賴任何實現給出的順序。 但是, SortedMap接口擴展了Map並提供了您正在尋找的內容 - 實現將提供一致的排序順序。

NavigableMap是另一個有用的擴展 - 這是一個SortedMap其中包含其他方法,用於按鍵集中的有序位置查找條目。 因此,這可能會消除首先進行迭代的需要 - 您可能能夠在使用higherEntrylowerEntryceilingEntryfloorEntry方法之後找到您所使用的特定entrydescendingMap方法甚至為您提供了一種反轉遍歷順序的顯式方法。


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

Java 8:

您可以使用lambda表達式:

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

有關更多信息,請按照this


使用Java 8:

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

嘗試使用Java 1.4:

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

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

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

  //...
}

是的,因為很多人都認為這是迭代Map的最佳方式。

但是如果map是null則有機會拋出nullpointerexception 。 不要忘記將null .check放入。

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = 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);
        }
    }
}

要么

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

迭代地圖的典型代碼是:

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都會更新。


排序將始終取決於具體的地圖實施。 使用Java 8,您可以使用以下任一方法:

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

要么:

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

結果將是相同的(相同的順序)。 由映射支持的entrySet,以便您獲得相同的順序。 第二個是方便的,因為它允許你使用lambdas,例如,如果你只想打印大於5的Integer對象:

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

下面的代碼顯示了LinkedHashMap和普通HashMap的迭代(示例)。 你會看到順序的不同:

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

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,


總結其他答案並將它們與我所知道的結合起來,我找到了10種主要方法(見下文)。 另外,我寫了一些性能測試(見下面的結果)。 例如,如果我們想要找到地圖的所有鍵和值的總和,我們可以寫:

  1. 使用iteratorMap.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. 使用foreachMap.Entry

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

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

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    
  5. 使用keySetiterator

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
    
  6. 使用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. 使用Java 8 Stream API

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

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

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

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

性能測試 (模式= AverageTime,system = Windows 8.1 64位,Intel i7-4790 3.60 GHz,16 GB)

  1. 對於小地圖(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. 對於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. 對於具有100000個元素的地圖,得分11​​84.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
    

圖表(性能測試取決於地圖大小)

表(性能測試取決於地圖大小)

          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

所有測試都在GitHub







iteration