跳轉到

Java基礎:集合框架概述

1. 簡介

Java 集合框架是 Java 標準庫中的一個重要組成部分,提供統一的架構來儲存和操作物件群組。這個框架包含多種介面、實現類別和演算法,使得程式設計師能夠更有效地處理資料集合。

集合框架的重要性體現在以下幾個方面:

  1. 提高程式效率:集合框架提供高效能的資料結構實現,可以提高程式的執行效率。

  2. 減少程式碼量:使用標準化的集合類別可以減少自定義資料結構的需求,從而減少程式碼量。

  3. 提高程式品質:集合框架經過充分測試和優化,使用可以提高程式的穩定性和可靠性。

  4. 促進程式碼重用:集合框架提供通用的介面和實現,可以在不同的專案中重複使用。

  5. 增強互操作性:使用標準集合類別可以使不同的 API 和程式碼庫更容易相互操作。

2. 集合框架的核心介面

Java 集合框架的核心是一系列定義不同類型集合的介面。這些介面為各種集合類別提供統一的操作方式。以下是最重要的幾個核心介面:

Collection 介面

Collection 是集合階層結構的根介面,定義所有集合都應該具有的基本操作,如新增、刪除、查詢等。

主要方法: - add(E e): 新增元素 - remove(Object o): 移除元素 - contains(Object o): 檢查是否包含某元素 - size(): 返回集合大小 - iterator(): 返回一個迭代器

List 介面

List 是有序集合的介面,允許重複元素,並可以通過索引訪問元素。

特有方法: - get(int index): 獲取指定索引的元素 - set(int index, E element): 替換指定索引的元素

Set 介面

Set 表示不允許重複元素的集合。

特點: - 不包含重複元素 - 通常不保證元素的順序

Map 介面

Map 表示鍵值對的集合,每個鍵映射到一個值。

主要方法: - put(K key, V value): 新增鍵值對 - get(Object key): 根據鍵獲取值 - remove(Object key): 移除指定鍵的鍵值對

Queue 介面

Queue 表示一個隊列,通常(但不一定)以 FIFO(先進先出)的方式排序元素。

特有方法: - offer(E e): 新增元素到隊列尾部 - poll(): 移除並返回隊列頭部的元素

這些核心介面為 Java 集合框架提供一個統一的結構,使得不同的集合類型可以以一致的方式被使用和操作。在接下來的章節中,我們將詳細介紹這些介面的具體實現類別。

3. List 實現類別

List 介面在 Java 集合框架中有幾個重要的實現類別,每個類別都有其特定的用途和特性。以下是最常用的 List 實現類別:

ArrayList

ArrayList 是最常用的 List 實現,基於動態陣列實現。

特點: - 隨機訪問元素的效率高(通過索引) - 在列表末尾新增/刪除元素的效率高 - 在列表中間插入/刪除元素的效率較低 - 非同步(不是執行緒安全的)

LinkedList

LinkedList 基於雙向鏈結串列實現。

特點: - 在列表的開頭和結尾新增/刪除元素的效率很高 - 隨機訪問元素的效率較低 - 比 ArrayList 佔用更多的記憶體 - 非同步

Vector

Vector 是一個舊的實現類別,類似於 ArrayList,但是同步的(執行緒安全)。

特點: - 所有方法都是同步的 - 效能較 ArrayList 差 - 除非需要執行緒安全,否則通常推薦使用 ArrayList

程式碼示例:ArrayList 的基本操作

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

public class ArrayListExample {
    public static void main(String[] args) {
        // 創建 ArrayList
        List<String> fruits = new ArrayList<>();

        // 新增元素
        fruits.add("蘋果");
        fruits.add("香蕉");
        fruits.add("橘子");

        // 訪問元素
        System.out.println("第二個水果是:" + fruits.get(1));

        // 修改元素
        fruits.set(1, "葡萄");

        // 刪除元素
        fruits.remove("橘子");

        // 遍歷列表
        System.out.println("水果列表:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }

        // 檢查是否包含某元素
        System.out.println("列表包含蘋果嗎? " + fruits.contains("蘋果"));

        // 獲取列表大小
        System.out.println("列表大小:" + fruits.size());
    }
}

這個例子展示 ArrayList 的基本操作,包括新增、訪問、修改、刪除元素,以及其他常用方法。在選擇使用哪種 List 實現時,需要考慮你的具體需求,如是否需要頻繁的隨機訪問、插入或刪除操作,以及是否需要執行緒安全性。

4. Set 實現類別

Set 介面的實現類別提供不允許重複元素的集合。以下是 Java 中最常用的 Set 實現類別:

HashSet

HashSet 是最常用的 Set 實現,使用哈希表來儲存元素。

特點: - 不保證元素的順序 - 允許 null 元素 - 提供最佳的性能 - 非同步(不是執行緒安全的)

TreeSet

TreeSet 基於紅黑樹實現,元素按照自然順序或指定的比較器排序。

特點: - 元素保持排序狀態 - 不允許 null 元素 - 相比 HashSet,新增和刪除操作的性能較低 - 非同步

LinkedHashSet

LinkedHashSet 是 HashSet 的子類別,使用鏈結串列來維護元素的插入順序。

特點: - 維護元素的插入順序 - 允許 null 元素 - 性能介於 HashSet 和 TreeSet 之間 - 非同步

程式碼示例:HashSet 的使用

import java.util.HashSet;
import java.util.Set;

public class HashSetExample {
    public static void main(String[] args) {
        // 創建 HashSet
        Set<String> fruits = new HashSet<>();

        // 新增元素
        fruits.add("蘋果");
        fruits.add("香蕉");
        fruits.add("橘子");
        fruits.add("蘋果");  // 重複元素,不會被添加

        // 遍歷集合
        System.out.println("水果集合:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }

        // 檢查元素是否存在
        System.out.println("集合包含葡萄嗎? " + fruits.contains("葡萄"));

        // 刪除元素
        fruits.remove("香蕉");

        // 獲取集合大小
        System.out.println("集合大小:" + fruits.size());

        // 清空集合
        fruits.clear();
        System.out.println("清空後的集合大小:" + fruits.size());
    }
}

這個例子展示 HashSet 的基本操作,包括新增元素(注意重複元素不會被添加)、遍歷集合、檢查元素存在性、刪除元素等。

選擇適當的 Set 實現取決於你的具體需求。如果不需要排序且要最佳性能,使用 HashSet;如果需要排序的集合,使用 TreeSet;如果需要保持插入順序,使用 LinkedHashSet。

5. Map 實現類別

Map 介面的實現類別提供鍵值對的儲存方式。以下是 Java 中最常用的 Map 實現類別:

HashMap

HashMap 是最常用的 Map 實現,使用哈希表來儲存鍵值對。

特點: - 不保證鍵值對的順序 - 允許 null 鍵和 null 值 - 提供最佳的性能 - 非同步(不是執行緒安全的)

TreeMap

TreeMap 基於紅黑樹實現,鍵值對按照鍵的自然順序或指定的比較器排序。

特點: - 鍵值對保持排序狀態(基於鍵) - 不允許 null 鍵,但允許 null 值 - 相比 HashMap,新增和刪除操作的性能較低 - 非同步

LinkedHashMap

LinkedHashMap 是 HashMap 的子類別,使用鏈結串列來維護鍵值對的插入順序。

特點: - 維護鍵值對的插入順序 - 允許 null 鍵和 null 值 - 性能介於 HashMap 和 TreeMap 之間 - 非同步

程式碼示例:HashMap 的基本操作

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

public class HashMapExample {
    public static void main(String[] args) {
        // 創建 HashMap
        Map<String, Integer> fruitPrices = new HashMap<>();

        // 新增鍵值對
        fruitPrices.put("蘋果", 30);
        fruitPrices.put("香蕉", 20);
        fruitPrices.put("橘子", 25);

        // 獲取值
        System.out.println("蘋果的價格:" + fruitPrices.get("蘋果"));

        // 修改值
        fruitPrices.put("蘋果", 35);

        // 檢查鍵是否存在
        System.out.println("是否有葡萄的價格? " + fruitPrices.containsKey("葡萄"));

        // 遍歷 Map
        System.out.println("所有水果價格:");
        for (Map.Entry<String, Integer> entry : fruitPrices.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        // 刪除鍵值對
        fruitPrices.remove("香蕉");

        // 獲取 Map 大小
        System.out.println("價目表大小:" + fruitPrices.size());
    }
}

這個例子展示 HashMap 的基本操作,包括新增鍵值對、獲取和修改值、檢查鍵的存在性、遍歷 Map 等。

選擇適當的 Map 實現取決於你的具體需求。如果不需要排序且要最佳性能,使用 HashMap;如果需要基於鍵排序的 Map,使用 TreeMap;如果需要保持插入順序,使用 LinkedHashMap。

6. Queue 實現類別

Queue 介面代表一個隊列,通常(但不總是)以先進先出(FIFO)的方式排序元素。Java 提供幾種 Queue 的實現,其中最常用的是 PriorityQueue 和 LinkedList(當作為 Queue 使用時)。

PriorityQueue

PriorityQueue 是一個基於優先堆的無界優先級隊列。

特點: - 元素按照自然順序或指定的比較器排序 - 不允許 null 元素 - 不保證具有相同優先級的元素的順序 - 非同步(不是執行緒安全的)

LinkedList 作為 Queue

LinkedList 實現 Queue 介面,可以用作一個標準的先進先出(FIFO)隊列。

特點: - 允許 null 元素 - 保持元素的插入順序 - 在隊列的兩端進行操作的效率很高 - 非同步

程式碼示例:PriorityQueue 的使用

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 創建 PriorityQueue
        Queue<Integer> numbers = new PriorityQueue<>();

        // 新增元素
        numbers.offer(5);
        numbers.offer(1);
        numbers.offer(3);
        numbers.offer(2);
        numbers.offer(4);

        System.out.println("優先級隊列內容:" + numbers);

        // 查看隊列頭部元素但不移除
        System.out.println("隊列頭部元素:" + numbers.peek());

        // 移除並返回隊列頭部元素
        System.out.println("移除的元素:" + numbers.poll());

        System.out.println("移除後的隊列:" + numbers);

        // 遍歷並移除所有元素
        System.out.println("按優先級順序移除元素:");
        while (!numbers.isEmpty()) {
            System.out.println(numbers.poll());
        }
    }
}

這個例子展示 PriorityQueue 的基本操作,包括新增元素、查看和移除隊列頭部元素,以及遍歷隊列。注意,雖然輸出的隊列內容可能看起來沒有排序,但當我們使用 poll() 方法移除元素時,會按照優先級順序(在這個例子中是自然數字順序)被移除。

Queue 的選擇取決於你的具體需求。如果需要元素按照優先級處理,使用 PriorityQueue;如果只需要標準的 FIFO 隊列,可以使用 LinkedList 作為 Queue 的實現。

7. 集合框架的工具類別

Java 集合框架提供兩個非常有用的工具類別:Collections 和 Arrays。這些類別包含許多靜態方法,可以幫助我們更方便地操作集合和陣列。

Collections 類別

Collections 類別提供一系列靜態方法,用於操作或返回集合。

主要功能: - 排序:sort() - 搜尋:binarySearch() - 修改:reverse(), shuffle(), fill() - 計算:max(), min() - 同步化:synchronizedList(), synchronizedSet(), synchronizedMap() - 不可修改的集合:unmodifiableList(), unmodifiableSet(), unmodifiableMap()

Arrays 類別

Arrays 類別提供一系列靜態方法,用於操作陣列。

主要功能: - 排序:sort() - 搜尋:binarySearch() - 比較:equals() - 填充:fill() - 轉換:asList()

程式碼示例:使用 Collections 類別的方法

import java.util.*;

public class CollectionsExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5));

        // 排序
        Collections.sort(numbers);
        System.out.println("排序後:" + numbers);

        // 二分搜尋(要求列表已排序)
        int index = Collections.binarySearch(numbers, 4);
        System.out.println("數字 4 的索引:" + index);

        // 反轉
        Collections.reverse(numbers);
        System.out.println("反轉後:" + numbers);

        // 洗牌
        Collections.shuffle(numbers);
        System.out.println("洗牌後:" + numbers);

        // 找最大值和最小值
        System.out.println("最大值:" + Collections.max(numbers));
        System.out.println("最小值:" + Collections.min(numbers));

        // 頻率
        System.out.println("數字 5 的出現次數:" + Collections.frequency(numbers, 5));

        // 不可修改的列表
        List<Integer> unmodifiableList = Collections.unmodifiableList(numbers);
        try {
            unmodifiableList.add(10); // 這會拋出 UnsupportedOperationException
        } catch (UnsupportedOperationException e) {
            System.out.println("不可修改的列表無法新增元素");
        }
    }
}

8. 選擇適當的集合類別

在 Java 程式設計中,選擇合適的集合類別對於程式的效能和可讀性至關重要。以下是一些選擇集合類別時需要考慮的因素:

性能考量

  1. 訪問時間:如果需要頻繁的隨機訪問,ArrayList 比 LinkedList 更合適。
  2. 插入/刪除效率:如果經常在集合的開頭或結尾進行插入/刪除操作,LinkedList 可能比 ArrayList 更好。
  3. 搜尋效率:對於頻繁的搜尋操作,HashSet 或 HashMap 通常是最佳選擇。

功能需求

  1. 是否需要保持元素順序:如果需要,考慮使用 LinkedHashSet 或 LinkedHashMap。
  2. 是否需要排序:如果需要自動排序,可以使用 TreeSet 或 TreeMap。
  3. 是否允許重複元素:如果不允許,使用 Set 的實現;如果允許,使用 List 的實現。
  4. 是否需要鍵值對儲存:如果需要,使用 Map 的實現。

常見使用場景

  1. 需要快速插入和刪除:LinkedList
  2. 需要快速隨機訪問:ArrayList
  3. 需要唯一元素集合:HashSet
  4. 需要排序的唯一元素集合:TreeSet
  5. 需要快速查找鍵值對:HashMap
  6. 需要排序的鍵值對:TreeMap
  7. 需要按優先級處理元素:PriorityQueue

選擇指南

  • 如果不確定使用哪種集合,ArrayList 通常是一個好的起點。
  • 如果需要映射結構,HashMap 通常是最佳選擇。
  • 如果需要集合(不允許重複),HashSet 是一個好的選擇。
  • 如果需要保證順序,考慮使用 LinkedHashMap 或 LinkedHashSet。
  • 如果需要排序,考慮使用 TreeMap 或 TreeSet。

本篇文章同步刊載iThome: iThome
筆者個人的網站: JUNYI