Map 作為 Java 集合框架的核心成員,遍歷操作頻率極高。JDK 5 引入增強 for 循環,JDK 8 帶來 Lambda 與 Stream API,讓遍歷方式更加多元。本文系統梳理四種主流遍歷姿勢,對比性能與適用場景,助你寫出更優雅、高效的代碼。
Map<String, Object> map = new HashMap<>();
map.put("name", "張三");
map.put("age", 25);
// 僅需 Key 時
for (String key : map.keySet()) {
System.out.println("Key: " + key);
}
// 需要 Value 時(需二次查找)
for (String key : map.keySet()) {
Object value = map.get(key);
System.out.println(key + " = " + value);
}
⚠ 注意:若 Map 定義為原始類型 Map map = new HashMap(),泛型擦除導致 Key 只能用 Object 接收,建議始終使用泛型聲明。
Map<Integer, String> weekMap = new LinkedHashMap<>();
weekMap.put(1, "週一");
weekMap.put(2, "週二");
// ... 至 7
for (Map.Entry<Integer, String> entry : weekMap.entrySet()) {
System.out.print(entry.getKey() + ":" + entry.getValue() + "\t");
}
// 輸出:1:週一 2:週二 3:週三 4:週四 5:週五 6:週六 7:週日
map.get(key) 的額外查找開銷// 單行式
weekMap.forEach((k, v) -> System.out.println(k + "=" + v));
// 多行式
weekMap.forEach((k, v) -> {
if (k % 2 == 0) System.out.println("雙數鍵: " + k + " -> " + v);
});
entrySet() 迭代器,性能與姿勢二相近// 篩選、轉換、收集
List<String> result = weekMap.entrySet().stream()
.filter(e -> e.getKey() > 3)
.map(e -> e.getKey() + ":" + e.getValue())
.collect(Collectors.toList());
// 並行處理大數據量 Map
weekMap.entrySet().parallelStream()
.forEach(entry -> heavyCompute(entry.getKey(), entry.getValue()));
| 方式 | 時間複雜度 | 適用場景 | 推薦指數 |
|---|---|---|---|
| keySet + get | O(n) + n×O(1) | 僅需 Key、或 Map 極小 | ★★☆ |
| entrySet (for-each) | O(n) | 通用首選、需 Key+Value | ★★★★★ |
| forEach + Lambda | O(n) | 簡單邏輯、代碼簡潔 | ★★★★☆ |
| Stream API | O(n) | 複雜管道操作、並行需求 | ★★★☆☆ |
map.put()/remove() 會拋 ConcurrentModificationException。解決:收集待處理 Key 到列表,遍歷後再操作;或用 ConcurrentHashMap。HashMap 允許 null Key/Value,Hashtable/ConcurrentHashMap 不允許,遍歷時需防空指針。LinkedHashMap,需自然序用 TreeMap,HashMap 無序。日常開發中,entrySet 增強 for 循環 是性能與可讀性的最佳平衡點;Lambda forEach 適合簡單邏輯快速編寫;Stream API 則是複雜數據處理管道的利器。根據業務複雜度、團隊代碼風格靈活選擇,才是成熟工程師的態度。