Map 遍歷是 Java 開發高頻操作。本文系統整理四種核心遍歷方式,深度分析 HashMap 與 TreeMap 下的效能差異,提供選型決策指南。
Map map = new HashMap<>();
map.put("a", "A");
map.put("b", "B");
map.put("c", "C");
// 1. keySet + 迭代器 (舊式)
Iterator it1 = map.keySet().iterator();
while (it1.hasNext()) {
String key = it1.next();
String value = (String) map.get(key);
System.out.println(value);
}
// 2. keySet + 增強 for (最常用)
for (String key : map.keySet()) {
String value = (String) map.get(key);
System.out.println(value);
}
// 3. entrySet + 迭代器
Iterator> it2 = map.entrySet().iterator();
while (it2.hasNext()) {
String value = (String) it2.next().getValue();
System.out.println(value);
}
// 4. entrySet + 增強 for (推薦同時取 key/value)
for (Map.Entry entry : map.entrySet()) {
String key = entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + "=" + value);
}
// 5. 僅遍歷 values
for (Object value : map.values()) {
System.out.println(value);
}
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 同時需 key & value | entrySet | 一次性取得 Entry 物件,避免額外 map.get(key) 雜湊查找 |
| 僅需 key | keySet | entrySet 會建立無用的 Entry 物件 |
| 僅需 value | values() | 最直接,無 key 開銷 |
關鍵洞察:當 key 極簡單 (如短字串、Integer) 時,keySet + get() 可能因避免建立 Entry 物件而略快 (~10%);但 key 複雜 (長字串、自定義物件、高碰撞) 時,entrySet 優勢明顯。綜合建議預設使用 entrySet。
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 同時需 key & value | entrySet (壓倒性優勢) | 樹查找 get(key) 為 O(log n),累積開銷遠大於 entrySet 一次遍歷 |
| 僅需 key | keySet | 同 HashMap |
| 僅需 value | values() | 同 HashMap |
結論:TreeMap 必須使用 entrySet 遍歷 key-value,效能差距可達數倍。
// 同時處理 key/value
map.forEach((k, v) -> System.out.println(k + "=" + v));
// 轉換為 List
List values = map.values().stream()
.map(Object::toString)
.collect(Collectors.toList());
// 過濾與轉換
Map filtered = map.entrySet().stream()
.filter(e -> e.getKey().startsWith("a"))
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));
遍歷過程中修改 Map 會拋出 ConcurrentModificationException (除非使用 ConcurrentHashMap)。
Iterator.remove() 或 ConcurrentHashMapConcurrentHashMap,其迭代器為弱一致性,不拋出 CME| 需求 | Map 類型 | 最佳方式 | 備註 |
|---|---|---|---|
| Key + Value | HashMap | entrySet + for-each | 預設首選 |
| Key + Value | TreeMap | entrySet + for-each | 強制,效能差距大 |
| 僅 Key | 所有 | keySet | |
| 僅 Value | 所有 | values() | |
| 需刪除 | 所有 | Iterator.remove() | 或 ConcurrentHashMap |
| 函數式/串流 | 所有 | forEach / stream() | Java 8+ |
原文測試顯示:HashMap 下 key 為簡單字串時 keySet 比 entrySet 快 ~10% (避免建立 Entry);但 key 複雜時 entrySet 勝出。TreeMap 下 entrySet 完勝。建議:預設用 entrySet,唯有確認 key 極簡單且僅遍歷 HashMap 時考慮 keySet。