CodeGym /課程 /JAVA 25 SELF /Map:HashMap 與 TreeMap,鍵與值

Map:HashMap 與 TreeMap,鍵與值

JAVA 25 SELF
等級 26 , 課堂 2
開放

1. 介紹

在真實世界中,我們經常需要把每個唯一的「鍵」對應到某個「值」。例如電話簿把人的名字對應到電話號碼,字典把單字對應到它的翻譯,成績表中每位學生都有自己的姓名與相應的分數。

在 Java 中,這類需求可以用介面 Map 來完成。它是用來儲存「鍵—值」配對(key-value pair)的集合。

Map 的主要特性:

  • 每個鍵都是唯一的(不允許重複)。
  • 一個鍵只能對應一個值。
  • 值可以重複。

打個比方:如果清單(List)就像餐廳的排隊(每個人站在自己的位置,可用索引取用),那映射(Map)就像有許多格子的櫃子:每個格子有一個號碼(鍵),裡面放著自己的東西(值)。

Map 介面:基本操作

介面 Map 宣告了處理鍵值配對的基本方法:

方法 說明
put(K key, V value)
依鍵新增/取代值
get(K key)
依鍵取得值
remove(K key)
依鍵刪除鍵值對
containsKey(K key)
檢查是否存在該鍵
containsValue(V value)
檢查是否存在該值
size()
映射中的鍵值對數量
isEmpty()
檢查 Map 是否為空
clear()
刪除所有鍵值對

型別 KV 是泛型參數:K(Key)是鍵的型別,V(Value)是值的型別。

3. 類別 HashMap:依鍵快速存取

什麼是 HashMap?

HashMapMap 介面最常見的實作。它能夠依鍵快速存取對應的值。

重要:HashMap 不保證元素的儲存順序!即使你以特定順序加入鍵,遍歷時也可能以不同順序出現。

如何建立 HashMap?

import java.util.HashMap;
import java.util.Map;

public class Example {
    public static void main(String[] args) {
        // 建立 Map:鍵為 String,值為 Integer
        Map<String, Integer> ages = new HashMap<>();

        // 新增元素
        ages.put("Vasya", 25);
        ages.put("Petya", 30);
        ages.put("Masha", 22);

        // 依鍵取得值
        int vasyaAge = ages.get("Vasya");
        System.out.println("Vasya 的年齡:" + vasyaAge); // 25

        // 檢查是否存在該鍵
        if (ages.containsKey("Masha")) {
            System.out.println("Masha 在清單中!");
        }

        // 刪除元素
        ages.remove("Petya");

        // 遍歷所有鍵值對
        for (String name : ages.keySet()) {
            System.out.println(name + ": " + ages.get(name));
        }
    }
}

輸出:

Vasya 的年齡:25
Masha 在清單中!
Vasya: 25
Masha: 22

HashMap 的特點

最需要記住的一點:HashMap 中的鍵必須唯一。如果你放入一個已存在的鍵,新值會覆蓋舊值。

值可以重複:多個不同的鍵可以對應到同一個值。

還有一點很重要——元素的順序。HashMap 不在乎加入順序。輸出時項目的排列可能是打亂的——這是正常行為。

4. 類別 TreeMap:依鍵排序

HashMap 不同,TreeMap 會依鍵的排序順序儲存元素。

何時使用 TreeMap?

當你需要元素依鍵遞增(或遞減)順序排列時。例如,你想按照字母順序輸出電話簿。

範例:

import java.util.Map;
import java.util.TreeMap;

public class TreeMapExample {
    public static void main(String[] args) {
        Map<String, String> phoneBook = new TreeMap<>();

        phoneBook.put("Vasya", "+1-900-123-45-67");
        phoneBook.put("Masha", "+1-900-555-55-55");
        phoneBook.put("Petya", "+1-900-222-33-44");

        for (String name : phoneBook.keySet()) {
            System.out.println(name + ": " + phoneBook.get(name));
        }
    }
}

輸出:

Masha: +1-900-555-55-55
Petya: +1-900-222-33-44
Vasya: +1-900-123-45-67

請注意:鍵是依字母順序排序的。

5. Map 的基本操作

新增與覆蓋元素
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Ivan", 85);
scores.put("Anna", 95); // 會覆蓋 'Anna' 的值
取得值
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("Vasya");   // null,如果沒有該鍵
檢查是否存在鍵或值
scores.containsKey("Ivan");    // true
scores.containsValue(85);      // true
依鍵刪除鍵值對
scores.remove("Ivan");
Map 的大小與清空
int size = scores.size();
scores.clear(); // 刪除所有元素

5. 迭代 Map 的元素

Map 不是清單,沒有索引。不過可以這樣遍歷:

按鍵:

for (String key : scores.keySet()) {
    System.out.println("鍵:" + key + ",值:" + scores.get(key));
}

按值:

for (Integer value : scores.values()) {
    System.out.println("值:" + value);
}

按鍵-值配對(最佳方式):

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

何時用 HashMap,何時用 TreeMap?

HashMap 幾乎是「預設」選擇。如果不在乎鍵的順序、而主要追求操作速度,幾乎總是用它。

當你需要有序時就用 TreeMap。它會自動以排序的鍵儲存資料,並能快速找到最小/最大鍵或處理區間。

總結:在 90% 的情況下選擇 HashMap。當資料一開始就需要「有序」時,使用 TreeMap

6. Map 的使用範例

範例 1:電話簿

Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Katya", "+1-999-111-22-33");
phoneBook.put("Oleg", "+1-999-222-33-44");
phoneBook.put("Katya", "+1-999-555-66-77"); // Katya 的舊號碼會被新號碼覆蓋

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

輸出:

Oleg: +1-999-222-33-44
Katya: +1-999-555-66-77

範例 2:統計單字出現次數

假設我們有一個單字清單,想知道每個單字出現了多少次:

import java.util.*;

public class WordCount {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("蘋果", "香蕉", "蘋果", "梨子", "香蕉", "蘋果");
        Map<String, Integer> counts = new HashMap<>();

        for (String word : words) {
            int oldCount = counts.getOrDefault(word, 0); // 若沒有該鍵則為 0
            counts.put(word, oldCount + 1);
        }

        System.out.println(counts); // {梨子=1, 蘋果=3, 香蕉=2}
    }
}

7. 使用 Map 時的常見錯誤

錯誤 №1:混淆鍵與值。 初學者常會嘗試像在清單一樣用索引取值,或忘了鍵必須唯一。在 Map 中沒有索引——只有鍵。

錯誤 №2:使用 null 鍵與值。HashMap 中允許鍵為 null,但在 TreeMap 中不行(會丟出 NullPointerException)。兩者的值都可以是 null,但實務上很少有幫助。

錯誤 №3:期望 HashMap 中的元素有序。 HashMap 並不保證任何順序。若需要順序——請使用 LinkedHashMap(維持加入順序)或 TreeMap(依鍵排序)。

錯誤 №4:遍歷時同時修改 Map。 如果你在迴圈中遍歷 Map 的同時新增/刪除元素,可能會發生 ConcurrentModificationException。這種情況請使用帶有 remove() 的迭代器,或使用專用的並發集合。

錯誤 №5:用 == 比較鍵與值,而不是 equals。 Map 會用 equals 方法比較鍵(和值)。如果你自己建立作為鍵的類別,務必覆寫 equalshashCode

1
任務
JAVA 25 SELF, 等級 26, 課堂 2
上鎖
智慧任務排程器:一週的日子 🗓️
智慧任務排程器:一週的日子 🗓️
1
任務
JAVA 25 SELF, 等級 26, 課堂 2
上鎖
倉庫水果按字母順序盤點 🍏🍌🍐
倉庫水果按字母順序盤點 🍏🍌🍐
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION