1. 前言
Java 中 List 的重要性是什麼?
在 Java 程式設計中,「List」是經常出現的資料結構。特別是在需要一次管理多個值的情況下,由於它比陣列更靈活且易於使用,因此在許多實際應用中受到青睞。
「List」是 Java 集合框架的核心介面,通過 ArrayList、LinkedList 等各種實作類別,建構了能應對多樣化情境的機制。數據的建立、刪除、搜尋、更新等操作可以直覺地進行,這也是 List 受到支持的原因之一。
本文的目的與目標讀者
本文將從基礎到應用,系統地、易於初學者理解的方式解說「Java List」。主要針對以下讀者:
- 剛開始學習 Java,對 List 的使用感到不安的人
- 想清楚理解陣列(Array)與 List 差異的人
- 正在煩惱如何區分使用 ArrayList 和 LinkedList 的人
- 想在實際工作中重新複習 List 基礎知識的人
希望讀完本文後,能確實掌握 Java 中 List 的基本概念、實作方法和具體操作,並能自信地進行程式編寫。
從下一章開始,將首先從「什麼是 List?」這個基本部分開始,依序進行說明。
2. 什麼是 List?
List 的概述與特點
在 Java 中,「List」是以順序保持元素的集合介面。最大的特點是,元素的增加順序會被保留,並且可以使用索引(從 0 開始)來存取個別元素。
List 作為集合框架的一部分提供,具有以下功能:
- 允許元素重複
- 可以通過指定索引來獲取、更新、刪除元素
- 可以動態地增加或減少元素數量(與陣列不同,不是固定長度)
這使得數據操作更加靈活,在實際工作中也經常使用。
與陣列(Array)的差異
在 Java 中,陣列(int[]
、String[]
等)也作為存放多個值的方式存在,但與 List 有一些不同之處。
比較項目 | 陣列(Array) | List |
---|---|---|
元素數量變更 | 不可(固定長度) | 可(可動態增減) |
提供的功能 | 最少的操作(索引存取、獲取長度) | 豐富的方法(add, remove, contains 等) |
型別 | 可以處理基本型別 | 僅限物件型別(需要使用包裹類別) |
型別安全性 | 陣列在編譯時進行型別檢查 | 可以使用泛型嚴格指定型別 |
因此,List 作為更靈活且功能更強大的集合,在許多情況下比陣列更具實用性。
List 介面及其實作類別
在 Java 中使用 List 時,通常使用 List
介面來宣告變數,並使用具體類別(實作類別)來建立實例。代表性的實作類別如下:
- ArrayList
結構類似於陣列,可以實現高速存取。擅長數據搜尋和隨機存取。 - LinkedList
每個元素都與前後元素相連。插入和刪除速度快,適合經常進行操作的列表。 - Vector
類似於 ArrayList,但它是執行緒安全的,相對來說效率較低。目前較少使用。
一般來說,除非有特殊原因,否則ArrayList 是最常用的。您可以根據用途參考後面的效能比較來區分使用。
3. List 的基本用法
本節將依序解說在 Java 中使用 List 的基本操作。這裡主要以ArrayList 為例,介紹 List 的代表性操作。
List 的宣告與初始化
首先,是使用 ArrayList
對 List 進行基本宣告與初始化。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
}
}
通常使用 List
介面宣告變數,並使用 ArrayList
建立實例。使用泛型指定要儲存的型別(這裡指定為 String
)。
元素的新增(add)
若要將元素新增至 List,請使用 add()
方法。
fruits.add("りんご");
fruits.add("バナナ");
fruits.add("みかん");
這樣,三個元素將依序新增到 List 中。List 會保留元素的增加順序。
元素的獲取(get)
若要獲取指定索引的元素,請使用 get(int index)
。
System.out.println(fruits.get(0)); // 「りんご」が表示される
請注意,索引是從 0 開始。
元素的更新(set)
若要更新某個位置的元素,請使用 set(int index, E element)
。
fruits.set(1, "ぶどう"); // 2番目の要素「バナナ」が「ぶどう」に置き換わる
元素的刪除(remove)
也可以刪除特定索引或元素本身。
fruits.remove(0); // 先頭の要素を削除
fruits.remove("みかん"); // 「みかん」を削除(最初に一致したものだけ)
獲取 List 的大小(size)
可以使用 size()
方法獲取當前元素的數量。
System.out.println(fruits.size()); // 2などが返る
檢查元素是否存在(contains)
若要檢查 List 是否包含特定元素,請使用 contains()
。
if (fruits.contains("ぶどう")) {
System.out.println("ぶどうはあります");
}
總結:常用基本操作一覽
操作 | 方法範例 | 說明 |
---|---|---|
新增 | add("元素") | 新增至最後 |
獲取 | get(索引) | 元素的參考 |
更新 | set(索引, 新元素) | 變更指定位置的元素 |
刪除 | remove(索引/元素) | 刪除指定的元素 |
獲取大小 | size() | 獲取元素數量 |
檢查存在 | contains("元素") | 確認特定元素是否存在 |
4. List 的操作範例
本章將介紹使用 Java List 的實際操作範例。需要依序處理列表內元素的情況非常多,這裡將介紹使用for 迴圈、增強型 for 迴圈、Stream API 的代表性方法。
使用 for 迴圈遍歷
最基本的方法是使用 for
迴圈,通過索引來取出元素。
List<String> fruits = new ArrayList<>();
fruits.add("りんご");
fruits.add("バナナ");
fruits.add("みかん");
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i));
}
這種方法可以進行精確的索引控制。例如,在只想處理偶數位置的元素時非常有效。
使用增強型 for 迴圈(for-each)遍歷
如果想不考慮索引,依序處理所有元素,那麼增強型 for 迴圈非常方便。
for (String fruit : fruits) {
System.out.println(fruit);
}
寫法簡單易讀,是最常用的方法之一。對於簡單的處理,這種方法足夠應付。
使用 Lambda 表達式和 Stream API 遍歷
從 Java 8 開始,也可以使用 Stream API 和 Lambda 表達式進行編寫。
fruits.stream().forEach(fruit -> System.out.println(fruit));
這種寫法的優點是可以將多個處理串連起來。例如,可以輕鬆地先根據特定條件過濾再輸出。
fruits.stream()
.filter(fruit -> fruit.contains("ん"))
.forEach(System.out::println);
這個範例中,只輸出包含「ん」的水果。特別推薦給想習慣函數式風格編程的人。
各種方法的區分使用
方法 | 優點 | 適用場景 |
---|---|---|
傳統 for 迴圈 | 可進行索引控制 | 需要元素編號的處理 |
增強型 for 迴圈 | 寫法簡單易讀 | 簡單的遍歷處理 |
Stream API | 擅長條件式處理和連續處理 | 想組合過濾、映射、聚合等操作的情況 |
5. ArrayList 與 LinkedList 的差異與區分使用
作為實作 Java List 介面的代表性類別,有ArrayList 和LinkedList。兩者都可以作為 List 使用,但由於內部結構和效能特性的差異,在適當的場合區分使用非常重要。
ArrayList 的特點與適用用途
ArrayList
內部使用動態陣列(可變長度陣列)。
主要特點:
- 隨機存取(指定索引)速度非常快
- 若為列表末尾新增元素速度快(平均 O(1))
- 中間插入或刪除會變慢(O(n))
適用場景:
- 經常進行搜尋(
get()
)的場景 - 元素數量可以在事前一定程度上預測的場景
- 元素新增和刪除較少,以讀取為主的處理
List<String> list = new ArrayList<>();
LinkedList 的特點與適用用途
LinkedList
使用雙向連結列表的結構實現。
主要特點:
- 元素的新增和刪除速度快(特別是開頭或結尾)
- 隨機存取(
get(index)
)速度慢(O(n)) - 記憶體消耗量比 ArrayList 稍微多一些
適用場景:
- 經常進行元素插入和刪除的場景(特別是開頭或中間)
- 想作為佇列(Queue)或堆疊(Stack)使用時
- 以疊代為主,不需要索引存取的情況
List<String> list = new LinkedList<>();
效能比較
下表顯示常用操作的理論計算複雜度(大 O 表示法)。
操作 | ArrayList | LinkedList |
---|---|---|
get(int index) | O(1) | O(n) |
add(E e) (末尾) | O(1) | O(1) |
add(int index, E e) | O(n) | O(n) |
remove(int index) | O(n) | O(n) |
疊代 | O(n) | O(n) |
※ 實際處理時間也受到數據大小、JVM 優化等因素影響。

實際應用中區分使用的重點
- 如果「將數據視為列表,並透過索引存取」,則使用 ArrayList
- 如果「經常在開頭或中間插入・刪除」,則使用 LinkedList
- 在效能要求嚴苛的處理中,務必進行基準測試並驗證
6. List 的進階用法
本節將介紹讓 Java List 使用更方便的進階技巧。List 不僅僅是數據的集合體,還可以通過排序、洗牌、過濾、轉換等方式進行多種處理。
List 的排序(Collections.sort)
使用 Collections.sort()
可以將 List 中的元素按升序排序。元素需要實作 Comparable
介面。
import java.util.*;
List<String> fruits = new ArrayList<>();
fruits.add("バナナ");
fruits.add("りんご");
fruits.add("みかん");
Collections.sort(fruits);
System.out.println(fruits); // [みかん, りんご, バナナ]
以自訂順序排序時(使用 Comparator)
fruits.sort(Comparator.reverseOrder()); // 降順に並び替え
List 的洗牌(Collections.shuffle)
若要隨機打亂元素的順序,可以使用 Collections.shuffle()
。
Collections.shuffle(fruits);
System.out.println(fruits); // [バナナ, みかん, りんご](例)
在需要遊戲牌組或隨機顯示順序時很方便。
使用 Stream API 過濾(filter)
使用 Java 8 開始的 Stream
,可以簡潔地編寫只提取符合條件的元素的處理。
List<String> filtered = fruits.stream()
.filter(fruit -> fruit.contains("ん"))
.collect(Collectors.toList());
System.out.println(filtered); // [みかん, りんご]
使用 Stream API 轉換(map)
若要將元素轉換為其他形式,請使用 map()
。
List<Integer> lengths = fruits.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths); // 各果物名の文字数 [3, 3, 2] など
map()
在數據的格式轉換和預處理中是強大的工具。
進階操作總結
操作 | 使用範例 | 主要用途 |
---|---|---|
排序 | Collections.sort(list) | 按升序排列 |
洗牌 | Collections.shuffle(list) | 隨機打亂元素的順序 |
過濾 | stream().filter(...).collect() | 只提取符合條件的元素 |
轉換 | stream().map(...).collect() | 轉換元素的型別或值 |
7. 常見錯誤及其處理方法
在使用 Java List 時,初學者特別容易遇到的問題是「例外(錯誤)」。這裡將具體解說實際上經常發生的代表性錯誤、其原因和解決方法。
IndexOutOfBoundsException(索引超出範圍錯誤)
發生原因:
嘗試存取不存在的索引時發生。
List<String> list = new ArrayList<>();
list.add("りんご");
System.out.println(list.get(1)); // エラー:Index 1 out of bounds
處理方法:
在存取前確認大小,或通過條件判斷來控制索引是否有效。
if (list.size() > 1) {
System.out.println(list.get(1));
}
NullPointerException(空指標例外)
發生原因:
在 List 本身或 List 的元素為 null
的狀態下呼叫方法時發生。
List<String> list = null;
list.add("りんご"); // NullPointerException発生
處理方法:
事先確認變數不是 null,或利用 Optional 等。
或者,注意不要忘記初始化:
List<String> list = new ArrayList<>(); // 正しい初期化
ConcurrentModificationException(並發修改例外)
發生原因:
在使用 for-each
迴圈或 Iterator
遍歷 List 時,直接修改 List 時發生。
for (String fruit : list) {
if (fruit.equals("バナナ")) {
list.remove(fruit); // ConcurrentModificationException
}
}
處理方法:
使用 Iterator
安全刪除,或使用 removeIf()
等方法。
或者,從 Java 8 開始可以更簡潔:
list.removeIf(fruit -> fruit.equals("バナナ"));
其他注意事項
- 確認 List 不是 null
- 理解索引從 0 開始
僅宣告變數但未使用的情況非常多。初始化是必須的。
這是初學者常見的錯誤,容易誤以為「第一個是索引 1」。
錯誤處理總結
錯誤名稱 | 主要原因 | 處理方法範例 |
---|---|---|
IndexOutOfBoundsException | 存取不存在的索引 | 使用 size() 確認長度 |
NullPointerException | List 或元素為 null | 不要忘記初始化,並進行 null 檢查 |
ConcurrentModificationException | 遍歷期間直接修改 List | 使用 Iterator 操作或利用 removeIf() |
8. 總結
回顧 Java List 的基礎知識
本文循序漸進地解說了 Java 中 List 的基礎到應用。List 在 Java 集合中是使用頻率特別高的,是靈活處理數據的重要工具。
首先,在掌握了什麼是 List 的基礎上,學習了以下重點:
- List 是有順序、允許重複的集合,可以進行索引操作
- 有ArrayList 和 LinkedList 兩個代表性的實作類別,特點和用途不同
- 掌握基本操作(新增、獲取、更新、刪除、搜尋)後,可以自由地操作數據
- for 迴圈、增強型 for 迴圈、Stream API 等,根據情況進行重複處理
- 也能應對排序、過濾、轉換等進階處理
- 理解常見錯誤及其原因和處理方法,可以預防問題發生
ArrayList 與 LinkedList 的區分使用
應該使用哪種 List 實作,根據處理內容和數據量適當選擇非常重要。以下判斷可作為參考:
- ArrayList:隨機存取多,以讀取為主
- LinkedList:經常發生插入・刪除,存取順序很重要
未來學習的方向
List 僅僅是 Java 集合的「入口」。為了處理更進階的數據結構和工具,建議深入理解以下類別和功能:
- Set・Map:管理唯一元素、鍵值對結構
- Collections 工具類別:排序、獲取最小・最大值等
- Stream API 的活用:引入函數式編程
- 泛型的理解:型別安全的集合操作
掌握 List 的基礎,Java 程式設計整體會變得更容易掌握。
常見問題(FAQ)
整理了關於 Java List 初學者特別容易疑問的重點。嚴選了實際工作中也經常遇到的內容。
Q1. Java 的 List 與陣列(Array)有什麼不同?
A. 陣列的元素數量是固定的,需要在宣告時決定大小。另一方面,List 的大小是可變的,可以靈活地新增或刪除元素。此外,List 提供了許多方便的方法(add
, remove
, contains
等),在可讀性和維護性方面也更優越。
Q2. ArrayList 與 LinkedList 應該使用哪一個?
A. 主要在隨機存取(指定索引獲取)較多的情況下適合使用 ArrayList
,在經常發生元素插入・刪除的情況下適合使用 LinkedList
。如果猶豫不決,通常從 ArrayList
開始使用。
Q3. List 可以存放基本型別(int 或 double 等)嗎?
A. 不能直接存放。Java 的 List 只能處理物件型別,因此對於 int
等基本型別,需要使用對應的包裹類別(Integer
, Double
等)。
List<Integer> numbers = new ArrayList<>();
numbers.add(10); // オートボクシングされてInteger型として格納される
Q4. 想對 List 中的元素進行排序,應該怎麼做?
A. 使用 Collections.sort(list)
可以按升序排序。此外,如果想按自訂順序排序,可以指定 Comparator
來自由排序。
Q5. 如果想管理不重複的元素,應該怎麼做?
A. List 是允許重複的集合。若要避免重複,請考慮使用 Set
(例如:HashSet
)。但需要注意,Set 不保證順序。如果想在 List 中排除重複,也可以使用如下的 Stream 處理:
List<String> distinctList = list.stream()
.distinct()
.collect(Collectors.toList());
Q6. 如果想清除 List 中的所有內容,應該怎麼做?
A. 使用 clear()
方法可以刪除 List 中的所有元素。
list.clear();
Q7. 在 List 中最常用的操作是什麼?
A. 在實際應用中最常用的是 add
(新增)、get
(獲取)、remove
(刪除)、size
(獲取大小)。掌握了這些,基本處理就可以幾乎涵蓋。