CodeGym /課程 /JAVA 25 SELF /Java 集合概覽 — 為什麼需要集合

Java 集合概覽 — 為什麼需要集合

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

1. 介紹

我們之前已經了解過「無限長的陣列」——也就是清單。現在讓我們更深入一些,先再問一次:什麼是「傳統」陣列?仔細一看,它像是一個有固定隔間數量的工具箱。假設箱子有 10 個格子。若你出現了第 11 個工具,怎麼辦?只好再買一個新箱子!傳統陣列的大小是固定的,建立之後長度就不會改變。

如果需要新增或刪除元素,就得建立新陣列並手動複製資料。陣列能夠快速透過索引找到元素,但要在中間插入元素並不是單純「插入」,而是「把右邊全部往右移」;刪除時則要「往左移」。這既慢又不方便。除此之外,陣列本身不包含任何額外的「邏輯」:它只是保存一組格子;排序、依內容搜尋或檢查唯一性都得靠外部手段完成。

範例:動態的學生清單

假設你在寫一個用於管理某個班級學生的應用程式。起初有 5 個人,接著又來了一位,然後有人離開。用陣列會是這樣:

String[] students = new String[5];
students[0] = "伊凡";
students[1] = "瑪麗亞";
// 以此類推...

// 糟了,又來了一位學生
// 只好建立新的陣列!
String[] newStudents = new String[6];
for (int i = 0; i < students.length; i++) {
    newStudents[i] = students[i];
}
newStudents[5] = "阿列克謝";
students = newStudents;

方便嗎?委婉地說,並不。若這類操作很多呢?你就會想要更方便的工具……

2. 什麼是集合?

集合是用來存放一組其他物件(元素)的容器。集合允許新增、刪除、遍歷元素,並執行其他操作:搜尋、排序、過濾等等。

在 Java 中,所有集合都會實作或繼承介面 Collection(而對映則是 Map)。集合不只是「一堆東西」,而是一個提供便利且設計良好方法的結構,用於操作元素。

為什麼集合是物件?

因為集合是以類別實作,所以你可以建立任何物件的集合、將它們組合、繼承、擴充,並在自己的類別與方法中使用。

範例:

import java.util.ArrayList;
import java.util.List;

List<String> students = new ArrayList<>();
students.add("伊凡");
students.add("瑪麗亞");
students.add("阿列克謝");

搞定!現在可以隨意新增學生,不必再擔心陣列大小。

3. 集合能解決的典型任務

集合是處理資料的瑞士刀。它們可以解決以下問題:

  • 儲存動態資料清單: 例如學生名單、排程中的工作、聊天訊息。
  • 搜尋與篩選: 快速找到元素、檢查其是否存在、取得符合某條件的所有元素。
  • 排序: 依所需準則輕鬆排序元素。
  • 新增與刪除元素: 可在集合的任意位置插入與刪除元素,而不需要手動複製陣列。
  • 依鍵分組: 例如電話簿,每個名字對應一個電話號碼。
  • 保證唯一性: 例如文字中所有不重複單字的集合。

範例:電話簿

用陣列:

  • 如何依名字找到號碼?得逐一遍歷陣列並比較名字。
  • 如何新增一組配對?必須擴充陣列。
  • 如何確保名字不重複?更麻煩。

用集合:

  • 使用 Map<String, String>,上述需求都能「開箱即用」。

4. 主要集合類型概覽

在 Java 中,集合大致分為三大類:

集合類型 介面/類別 用途
清單 List, ArrayList 有序的元素集合,允許重複,支援索引存取
集合(Set) Set, HashSet 只保存唯一元素,不保證順序
對映 Map, HashMap 儲存鍵-值對,依鍵快速查找

清單(List

  • 有序的集合,允許重複。
  • 可透過索引取得元素。
  • 範例:ArrayListLinkedList

集合(Set

  • 只保存唯一元素。
  • 不支援索引存取。
  • 範例:HashSetTreeSet

對映(Map

  • 儲存鍵-值對。
  • 依鍵快速查找。
  • 範例:HashMapTreeMap

視覺化示意(非常粗略):

+------------------+       +-------------------+      +---------------------+
|     List         |       |        Set        |      |         Map         |
|------------------|       |-------------------|      |---------------------|
| [a, b, c, d, a]  |       | {a, b, c, d}      |      | {a=1, b=2, c=3}     |
| 索引:有         |       | 索引:無          |      | 依鍵查找            |
| 重複:可         |       | 重複:不可        |      | 鍵唯一              |
+------------------+       +-------------------+      +---------------------+

5. 實用細節

何時使用哪一種集合?

List —— 當元素順序重要、需要允許重複、需要索引存取時(例如待辦清單、訊息歷史)。

Set —— 當只需要唯一元素且不在乎順序時(例如唯一使用者的集合)。

Map —— 當需要將鍵與值配對時(例如電話簿:名字是鍵,電話是值)。

生活中的比喻

List —— 自助餐的排隊:先到先服務,也能重複排隊(允許重複)。

Set —— 派對賓客名單:每位賓客只會出現一次(唯一)。

Map —— 通訊錄:每個名字都有自己的電話。

速查表:集合 vs 陣列

陣列(int[] 集合(List<Integer>
大小 固定 動態
新增元素 麻煩 簡單:add()
刪除元素 麻煩 簡單:remove()
依值查找 手動逐一檢查 方法:contains()
排序 使用 Arrays.sort() 使用 Collections.sort(),或集合的方法
唯一性支援 使用 Set
鍵-值對 使用 Map

6. 集合與 OOP 的關係

集合是實作特定介面(ListSetMap)的物件。這代表你可以:

  • 在集合中存放任何物件,包括你自訂類別的實例。
  • 建立集合的集合(例如清單的清單)。
  • 將集合用作方法參數與回傳值。
  • 透過繼承與組合擴充集合的功能。

範例:自訂類別物件的集合

import java.util.ArrayList;
import java.util.List;

class Student {
    String name;
    int age;
    // 建構子、getter/setter 等等
}

public class Main {
    public static void main(String[] args) {
        List<Student> group = new ArrayList<>();
        group.add(new Student("伊凡", 20));
        group.add(new Student("瑪麗亞", 21));
        // 以此類推...
    }
}

7. 使用集合時的常見錯誤

錯誤 №1:使用未指定型別的集合(raw types)。
如果你寫的是 ArrayList list = new ArrayList(),那麼新增任何物件(例如字串與數字混在一起)時編譯器都不會報錯,但之後嘗試取出元素並轉型成需要的型別時,就可能在執行期發生錯誤(ClassCastException)。務必使用泛型:ArrayList<String> list = new ArrayList<>()

錯誤 №2:忘了匯入所需類別。
如果你看到「cannot find symbol」的錯誤,請確認檔案開頭有 import java.util.ArrayList; 或你的集合所需的匯入。

錯誤 №3:混淆集合與陣列。
集合不是陣列!集合沒有 length 欄位,請改用 size() 方法。陣列沒有 add() 方法,而集合沒有用於索引存取的 [] 運算子(只有清單可以透過 get(index) 取得)。

錯誤 №4:以為元素順序一定會被保留。
如果你使用 SetMap,元素的順序並不保證(除非使用像 LinkedHashSetTreeMap 這類特殊實作)。若需要有序資料,請使用 List 或相應的集合。

錯誤 №5:在集合中使用基本型別。
集合只能保存物件,不能保存基本型別。也就是說不能建立 List<int>,只能 List<Integer>。別忘了包裝類別!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION