1. 什麼是 Collection 介面
在 Java 中,介面就像契約:如果類別實作介面,就必須提供該介面所有方法的實作。介面本身不保存狀態,也不包含程式碼(幾乎如此:自 Java 8 起允許有 default 方法,但此處重點在於基本概念)。
Collection 是 Java 中多數集合的基礎介面。它定義了集合能做的事:新增元素、刪除元素、取得大小、檢查是否包含元素等。
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
boolean add(E e);
boolean remove(Object o);
void clear();
Iterator<E> iterator();
// ... 還有一堆實用的方法
}
關鍵方法:
- add(E e) — 新增元素。
- remove(Object o) — 刪除元素。
- size() — 取得元素數量。
- isEmpty() — 檢查集合是否為空。
- contains(Object o) — 檢查是否包含某元素。
- clear() — 清空集合。
- iterator() — 取得可用於迭代的迭代器。
為什麼 Map 不繼承 Collection?
Map 在集合中是獨立的一支。因為 Map 是由「鍵 → 值」配對組成,而不是單純的元素集合。它有不同的契約與方法集合。比如在 Map 中沒有 add 方法,因為新增是透過 put(key, value) 完成;此外,不知道鍵時去檢查值是否存在也沒有意義。
2. 集合的階層結構
可以想像主要介面的「樹狀」結構如下:
Iterable
|
Collection
/ | \
List Set Queue
|
Deque
- Iterable — 最底層的介面:凡是能在 for-each 迴圈中迭代的東西。
- Collection — 擴充自 Iterable,新增了對元素集合進行操作的方法。
- 三大分支:
- List — 有序列表,允許重複。
- Set — 唯一元素的集合,順序取決於實作。
- Queue — 佇列(通常是 FIFO);其子類為 Deque(雙端佇列)。
而 Map 是獨立的一支:
Map
/ \
HashMap TreeMap
階層可視化(示意圖)
+--------------------+
| Iterable<E> |
+--------------------+
|
+--------------------+
| Collection<E> |
+--------------------+
/ | \
+--------+ +-------+ +-------+
| List | | Set | | Queue |
+--------+ +-------+ +-------+
|
+------+
|Deque |
+------+
+--------------------+
| Map<K,V> |
+--------------------+
3. List:有序且允許重複的集合
List 是一種集合,其特性為:
- 元素的順序很重要(第一個、第二個、第三個…)。
- 允許相同元素(可有重複)。
- 可透過索引取得元素(如 list.get(2))、替換、或插入到任意位置。
實作範例: ArrayList — 以索引存取很快;LinkedList — 適合在中間頻繁插入/刪除的情境。
import java.util.*;
List<String> shoppingList = new ArrayList<>();
shoppingList.add("牛奶");
shoppingList.add("麵包");
shoppingList.add("起司");
shoppingList.add("麵包"); // 允許重複!
System.out.println(shoppingList.get(1)); // "麵包"
List 的常用方法:
- add(E e)、add(int index, E e)
- get(int index)、set(int index, E e)
- remove(int index)、remove(Object o)
- indexOf(Object o)、lastIndexOf(Object o)
4. Set:唯一元素的集合
Set 是一種集合,其特性為:
- 每個元素皆唯一(不允許重複)。
- HashSet 不保證順序,TreeSet 可排序,LinkedHashSet 保留插入順序。
實作範例: HashSet、TreeSet、LinkedHashSet。
import java.util.*;
Set<String> uniqueNames = new HashSet<>();
uniqueNames.add("安雅");
uniqueNames.add("鮑里斯");
uniqueNames.add("安雅"); // 不會加入—已經存在!
System.out.println(uniqueNames.contains("安雅")); // true
System.out.println(uniqueNames.size()); // 2
Set 的常用方法:
- add(E e)、remove(Object o)
- contains(Object o)
- size()、isEmpty()
5. Map:鍵值對的集合
Map 是一種集合,其特性為:
- 每個元素都是一組鍵 → 值配對。
- 鍵必須唯一,值可以重複。
- 可透過鍵進行快速存取。
實作範例: HashMap、TreeMap、LinkedHashMap。
import java.util.*;
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("安雅", "+19991112233");
phoneBook.put("鮑里斯", "+19994445566");
phoneBook.put("安雅", "+19990001122"); // 會覆寫安雅的號碼!
System.out.println(phoneBook.get("安雅")); // "+19990001122"
System.out.println(phoneBook.containsKey("鮑里斯")); // true
Map 的常用方法:
- put(K key, V value)、get(K key)
- remove(K key)
- containsKey(K key)、containsValue(V value)
- keySet()、values()、entrySet()
6. 階層可視化:一圖看懂
簡要匯總表:
| 介面 | 說明 | 實作範例 | 關鍵特性 |
|---|---|---|---|
|
有序清單 | |
可依索引存取,允許重複 |
|
唯一值的集合 | |
只允許唯一元素 |
|
鍵值對 | |
鍵唯一,值可重複 |
階層示意:
Collection
/ | \
List Set Queue
|
Deque
Map(獨立)
7. 何時使用哪個介面
List
- 當元素的順序很重要時(例如使用者操作歷史)。
- 當需要重複元素時(例如訂單項目)。
- 當需要快速依索引存取/替換時。
Set
- 當需要唯一性時(email、登入名稱、id)。
- 當不在意順序,或反過來—需要自動排序的集合(TreeSet)。
Map
- 當需要對應鍵與值時(id → 物件,登入 → 個人檔案)。
- 當需要以鍵快速查找時。
- 當鍵必須唯一而值不必唯一時。
8. 使用集合階層的常見錯誤
錯誤 1:在變數宣告時使用了錯誤的介面。 如果你寫 ArrayList<String> list = new ArrayList<>();,就把自己綁死在某個實作上。更好的做法是 List<String> list = new ArrayList<>();——如此更容易替換實作。
錯誤 2:嘗試在 Set 中加入重複元素並期待它們會出現。 這不是 bug,而是設計特性:Set 依定義就不保存重複元素。重複插入會被忽略。
錯誤 3:把 Map 當成一般集合來用。 Map 既不是列表也不是集合。要遍歷時請使用 keySet()、values() 或 entrySet()。
錯誤 4:在 HashSet 或 HashMap 中期待有順序。 HashSet 和 HashMap 不保證順序。若順序很重要—請使用 LinkedHashSet 或 LinkedHashMap。
錯誤 5:為了唯一元素而使用 List。 若需要唯一性—請使用 Set。List 不會避免重複。
GO TO FULL VERSION