Java HashMap的keySet()迭代順序是否一致?



Answers

如果需要迭代順序不變的HashMap,可以使用LinkedHashMap

此外,如果您遍歷集合,則應始終使用它。 迭代HashMap的entrySet或keySet比使用LinkedHashMap慢得多。

Question

我知道從Map的keySet()方法返回的Set不保證任何特定的順序。

我的問題是,它是否保證多次迭代的相同順序。 例如

Map<K,V> map = getMap();

for( K k : map.keySet() )
{
}

...

for( K k : map.keySet() )
{
}

在上面的代碼中,假設未修改映射,keySet上的迭代是否會以相同的順序進行。 使用Sun的jdk15它以相同的順序迭代,但在我依賴這種行為之前,我想知道所有JDK是否也會這樣做。

編輯

我從答案中看到我不能依賴它。 太糟糕了。 我希望不必為了保證我的訂購而建立一些新的收藏品。 我的代碼需要迭代,執行一些邏輯,然後使用相同的順序再次迭代。 我將從keySet創建一個新的ArrayList,這將保證順序。




我同意LinkedHashMap的觀點。 當我試圖通過鍵對HashMap進行排序時,只是在我遇到問題的時候把我的發現和經驗。

我創建HashMap的代碼:

HashMap<Integer, String> map;

@Before
public void initData() {
    map = new HashMap<>();

    map.put(55, "John");
    map.put(22, "Apple");
    map.put(66, "Earl");
    map.put(77, "Pearl");
    map.put(12, "George");
    map.put(6, "Rocky");

}

我有一個函數showMap打印map的條目:

public void showMap (Map<Integer, String> map1) {
    for (Map.Entry<Integer,  String> entry: map1.entrySet()) {
        System.out.println("[Key: "+entry.getKey()+ " , "+"Value: "+entry.getValue() +"] ");

    }

}

現在,當我在排序之前打印地圖時,它會按以下順序打印:

Map before sorting : 
[Key: 66 , Value: Earl] 
[Key: 22 , Value: Apple] 
[Key: 6 , Value: Rocky] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

這與放置地圖鍵的順序基本不同。

現在當我用地圖鍵排序時:

    List<Map.Entry<Integer, String>> entries = new ArrayList<>(map.entrySet());

    Collections.sort(entries, new Comparator<Entry<Integer, String>>() {

        @Override
        public int compare(Entry<Integer, String> o1, Entry<Integer, String> o2) {

            return o1.getKey().compareTo(o2.getKey());
        }
    });

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

出局是:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 66 , Value: Earl] 
[Key: 6 , Value: Rocky] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

您可以按鍵的順序查看差異。 鍵的排序順序很好,但複製的地圖的鍵的順序再次與早期地圖的順序相同。 我不知道這是否有效,但對於具有相同鍵的兩個hashmap,鍵的順序是相同的。 這意味著對於兩個具有相同鍵的映射不能保證密鑰順序的說法,因為如果該JVM版本的HashMap實現,密鑰插入算法的固有性質。

現在當我使用LinkedHashMap將已排序的條目複製到HashMap時,我得到了期望的結果(這很自然,但這不是重點。點是關於HashMap鍵的順序)

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

輸出:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 6 , Value: Rocky] 
[Key: 12 , Value: George] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 66 , Value: Earl] 
[Key: 77 , Value: Pearl] 



即使在同一對像上多次調用方法之間,Map for Map也不保證任何順序。

在實踐中,如果迭代順序為多個後續調用而改變(假設地圖本身之間沒有變化),我會非常驚訝 - 但你不應該(並且根據API不能)依賴於此。

編輯 - 如果你想依賴迭代順序是一致的,那麼你需要一個SortedMap ,它提供了這些保證。




Hashmap不保證地圖的順序會隨著時間的推移保持不變。




Map是一個接口,它沒有在文檔中定義順序應該是相同的。 這意味著你不能依賴訂單。 但是如果你控制getMap()返回的Map實現,那麼你可以使用LinkedHashMap或TreeMap,並在你遍歷它們時獲得相同的鍵/值順序。




Links