HashMap 是 Java 集合框架中最高頻使用的鍵值存儲結構。本文匯總字符統計、多種遍歷方式、按 Value 排序等實戰場景,並解析底層原理與性能優化要點。
public class FrequencyCounter {
public static void main(String[] args) {
String text = "abcabcabcghgk";
Map<Character, Integer> freqMap = new HashMap<>();
for (char c : text.toCharArray()) {
// Java 8+ merge 方法原子化更新,簡潔高效
freqMap.merge(c, 1, Integer::sum);
}
// 輸出結果
freqMap.forEach((k, v) -> System.out.println(k + " : " + v));
}
}
/* 輸出:
a : 3
b : 3
c : 3
g : 2
h : 1
k : 1
*/
| 方式 | 代碼示例 | 特點 | 推薦場景 |
|---|---|---|---|
| EntrySet + 迭代器 | for (Entry<K,V> e : map.entrySet()) |
標準、可刪除、JDK 1.4+ | 通用遍歷、需移除元素 |
| KeySet + get | for (K k : map.keySet()) map.get(k) |
兩次查找、性能較差 | 僅需 Key 時 |
| forEach (Java 8) | map.forEach((k,v) -> ...) |
函數式、不可刪除、可能較慢 | 簡單只讀操作 |
| Stream API | map.entrySet().stream()... |
支持並行、鏈式操作 | 複雜篩選/轉換/聚合 |
// 安全刪除遍歷中的元素(避免 ConcurrentModificationException)
Iterator<Entry<K, V>> it = map.entrySet().iterator();
while (it.hasNext()) {
Entry<K, V> entry = it.next();
if (shouldRemove(entry)) {
it.remove(); // 唯一安全的刪除方式
}
}
推薦方案:TreeMap + 自定義 Comparator,或 Java 8 Stream 排序:
// 方案一:TreeMap + Comparator(穩定排序,保留鍵值關聯)
Map<String, Integer> countMap = new HashMap<>();
countMap.put("a", 10);
countMap.put("b", 20);
countMap.put("c", 5);
ValueComparator vc = new ValueComparator(countMap);
TreeMap<String, Integer> sortedMap = new TreeMap<>(vc);
sortedMap.putAll(countMap); // 按 Value 降序:b(20), a(10), c(5)
// Comparator 實現
class ValueComparator implements Comparator<String> {
Map<String, Integer> base;
public ValueComparator(Map<String, Integer> base) { this.base = base; }
@Override
public int compare(String a, String b) {
// 降序:大的在前
return base.get(b).compareTo(base.get(a));
// 注意:返回 0 會導致鍵合併,需處理值相等情況
}
}
// 方案二:Stream API(更現代、靈活、無需額外類)
List<Entry<String, Integer>> topList = countMap.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(10) // Top 10
.collect(Collectors.toList());
topList.forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
| 參數 | 默認值 | 調優建議 |
|---|---|---|
| 初始容量 | 16 | 預估數據量 new HashMap<>(expectedSize),避免擴容 |
| 負載因子 | 0.75 | 時間換空間:降低(如 0.5)減少碰撞;空間換時間:提高(如 0.9) |
| 樹化閾值 | 8 | 鏈表長度達 8 轉紅黑樹,防止哈希攻擊 |
hashCode() 和 equals(),且字段不可變(String/Integer/包裝類安全)。ConcurrentHashMap,Collections.synchronizedMap 性能差。HashMap 實現 Serializable,但 transient 修飾的 table 字段需特殊處理。Iterator.remove() 或 computeIfPresent 等原子方法修改。