Java 集合实战宝典:选对类型事半功倍
Java 集合框架是 Java 编程中不可或缺的一部分,它为开发者提供了多种数据结构来存储和操作对象集合。本文将全面介绍 Java 集合的类型、特点、应用场景,并通过实战代码示例帮助你深入理解每种集合的用法。
1. Java 集合框架概述
Java 集合框架位于 java.util
包中,主要由 Collection 和 Map 两大接口组成:
- Collection:集合的根接口,包含
List
(列表)、Set
(集合)和Queue
(队列)等子接口。 - Map:用于存储键值对的接口,不继承自
Collection
。
1.1 Collection 接口
- List:有序集合,允许重复元素。常见实现:
ArrayList
、LinkedList
、Vector
。 - Set:无序集合,不允许重复元素。常见实现:
HashSet
、LinkedHashSet
、TreeSet
。 - Queue:队列接口,支持 FIFO(先进先出)操作。常见实现:
PriorityQueue
、ArrayDeque
。
1.2 Map 接口
- Map:键值对存储,键唯一,值可重复。常见实现:
HashMap
、LinkedHashMap
、TreeMap
、Hashtable
。
2. Java 集合的分类与对比
以下是常见集合的对比表格,涵盖底层实现、特点、线程安全性和应用场景:
集合类型 | 底层实现 | 特点 | 线程安全 | 应用场景 |
---|---|---|---|---|
ArrayList | 动态数组 | 快速随机访问,插入/删除较慢 | 否 | 频繁读取、随机访问 |
LinkedList | 双向链表 | 快速插入/删除,随机访问较慢 | 否 | 频繁插入/删除操作 |
Vector | 动态数组 | 线程安全,性能较低 | 是 | 早期多线程环境(现不推荐) |
HashSet | 哈希表 | 无序,快速查找/插入/删除 | 否 | 去重、快速查找 |
LinkedHashSet | 哈希表 + 链表 | 插入顺序,快速查找/插入/删除 | 否 | 需维护插入顺序的去重集合 |
TreeSet | 红黑树 | 自动排序,范围查询 | 否 | 需要排序的集合 |
PriorityQueue | 堆 | 优先级队列,自动排序 | 否 | 任务调度、事件处理 |
ArrayDeque | 循环数组 | 双端队列,高效头尾操作 | 否 | 队列、栈、双端队列 |
HashMap | 哈希表 | 快速键值对存储/查找 | 否 | 键值对存储、缓存 |
LinkedHashMap | 哈希表 + 链表 | 维护插入或访问顺序 | 否 | LRU 缓存、按顺序遍历的配置项 |
TreeMap | 红黑树 | 键自动排序,范围查询 | 否 | 需要排序的键值对 |
Hashtable | 哈希表 | 线程安全,性能较低 | 是 | 早期多线程环境(现不推荐) |
3. 集合的应用场景与实战代码
以下通过代码示例展示每种集合的典型用法,代码包含详细注释,确保易于理解。
3.1 List(列表)
3.1.1 ArrayList
- 特点:基于动态数组实现,支持快速随机访问。
- 应用场景:存储大量数据并频繁访问,如用户列表、商品目录。
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
// 创建一个 ArrayList 存储学生姓名
List<String> students = new ArrayList<>();
students.add("Alice"); // 添加元素到末尾
students.add("Bob");
students.add("Charlie");
// 访问元素(快速随机访问,时间复杂度 O(1))
System.out.println("第一个学生: " + students.get(0)); // 输出: Alice
// 遍历列表
for (String student : students) {
System.out.println(student);
}
// 输出:
// Alice
// Bob
// Charlie
}
}
3.1.2 LinkedList
- 特点:基于双向链表实现,适合频繁插入和删除操作。
- 应用场景:任务队列、历史记录等动态变化的场景。
import java.util.LinkedList;
import java.util.List;
public class LinkedListExample {
public static void main(String[] args) {
// 创建一个 LinkedList 存储任务
List<String> tasks = new LinkedList<>();
tasks.add("Task 1");
tasks.add("Task 2");
tasks.add("Task 3");
// 在开头插入任务(高效,时间复杂度 O(1))
((LinkedList<String>) tasks).addFirst("Urgent Task");
// 移除最后一个任务(高效,时间复杂度 O(1))
((LinkedList<String>) tasks).removeLast();
// 遍历任务
for (String task : tasks) {
System.out.println(task);
}
// 输出:
// Urgent Task
// Task 1
// Task 2
}
}
3.2 Set(集合)
3.2.1 HashSet
- 特点:基于哈希表实现,元素无序,自动去重。
- 应用场景:唯一性检查、集合运算。
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
// 创建一个 HashSet 存储唯一数字
Set<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(2); // 重复元素不会被添加
// 检查元素是否存在(快速查找,时间复杂度 O(1))
System.out.println("是否包含 2: " + numbers.contains(2)); // 输出: true
// 遍历集合(无序)
for (int number : numbers) {
System.out.println(number);
}
// 输出(顺序不固定):
// 1
// 2
// 3
}
}
3.2.2 TreeSet
- 特点:基于红黑树实现,元素自动排序。
- 应用场景:需要排序的集合,如排行榜、字典序列表。
import java.util.Set;
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
// 创建一个 TreeSet 存储按字母顺序排序的姓名
Set<String> names = new TreeSet<>();
names.add("Charlie");
names.add("Alice");
names.add("Bob");
// 遍历集合,元素将按自然顺序输出(时间复杂度 O(log n) 插入)
for (String name : names) {
System.out.println(name);
}
// 输出:
// Alice
// Bob
// Charlie
}
}
3.3 Queue(队列)
3.3.1 PriorityQueue
- 特点:基于堆实现,提供优先级队列功能,元素按自然顺序或自定义顺序出队。
- 应用场景:任务调度、事件处理。
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueExample {
public static void main(String[] args) {
// 创建一个 PriorityQueue 存储按优先级排序的任务(自然顺序:字典序)
Queue<String> tasks = new PriorityQueue<>();
tasks.add("Task 3");
tasks.add("Task 1");
tasks.add("Task 2");
// 按优先级出队(最小元素先出,时间复杂度 O(log n))
while (!tasks.isEmpty()) {
System.out.println(tasks.poll());
}
// 输出:
// Task 1
// Task 2
// Task 3
}
}
3.3.2 ArrayDeque
- 特点:基于循环数组实现,支持双端队列操作,适合队列和栈。
- 应用场景:广度优先搜索、undo 功能。
import java.util.ArrayDeque;
import java.util.Deque;
public class ArrayDequeExample {
public static void main(String[] args) {
// 创建一个 ArrayDeque 作为栈使用(后进先出)
Deque<String> stack = new ArrayDeque<>();
stack.push("First"); // 入栈
stack.push("Second");
stack.push("Third");
// 弹出元素(时间复杂度 O(1))
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
// 输出:
// Third
// Second
// First
}
}
3.4 Map(映射)
3.4.1 HashMap
- 特点:基于哈希表实现,键值对无序,快速插入和查找。
- 应用场景:键值对存储、缓存。
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
// 创建一个 HashMap 存储学生成绩
Map<String, Integer> grades = new HashMap<>();
grades.put("Alice", 90); // 添加键值对
grades.put("Bob", 85);
grades.put("Charlie", 95);
// 获取成绩(快速查找,时间复杂度 O(1))
System.out.println("Alice 的成绩: " + grades.get("Alice")); // 输出: 90
// 遍历 Map(无序)
for (Map.Entry<String, Integer> entry : grades.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 输出(顺序不固定):
// Alice: 90
// Bob: 85
// Charlie: 95
}
}
3.4.2 LinkedHashMap
- 特点:继承自
HashMap
,维护键值对的插入顺序或访问顺序。 - 应用场景:LRU 缓存、按顺序遍历的配置项。
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapExample {
public static void main(String[] args) {
// 创建一个 LinkedHashMap 存储按插入顺序的配置项
Map<String, String> config = new LinkedHashMap<>();
config.put("host", "localhost");
config.put("port", "8080");
config.put("timeout", "30");
// 遍历 Map,元素将按插入顺序输出
for (Map.Entry<String, String> entry : config.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 输出:
// host: localhost
// port: 8080
// timeout: 30
}
}
3.4.3 TreeMap
- 特点:基于红黑树实现,键按自然顺序或自定义顺序排序。
- 应用场景:需要排序的键值对,如按键排序的字典。
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
// 创建一个 TreeMap 存储按键排序的配置项
Map<String, String> config = new TreeMap<>();
config.put("host", "localhost");
config.put("port", "8080");
config.put("timeout", "30");
// 遍历 Map,元素将按键的自然顺序输出(时间复杂度 O(log n))
for (Map.Entry<String, String> entry : config.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 输出:
// host: localhost
// port: 8080
// timeout: 30
}
}
4. 集合的优缺点与适用场景总结
集合类型 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
ArrayList | 快速随机访问(O(1)) | 插入/删除可能导致扩容或移动(O(n)) | 用户列表、商品目录等读取频繁场景 |
LinkedList | 插入/删除高效(O(1)) | 随机访问性能差(O(n)) | 任务队列、历史记录等动态变化场景 |
HashSet | 快速查找/插入/删除(O(1)),自动去重 | 无序,不支持索引访问 | 唯一性检查、集合运算 |
TreeSet | 自动排序,支持范围查询(O(log n)) | 插入/删除较慢(O(log n)) | 排行榜、字典序列表 |
PriorityQueue | 自动按优先级排序(O(log n) 出队) | 不稳定(相同优先级顺序不固定) | 任务调度、事件处理 |
ArrayDeque | 高效双端队列和栈操作(O(1)) | 不支持随机访问 | 广度优先搜索、undo 功能 |
HashMap | 快速键值对存储/查找(O(1)) | 无序,键必须唯一 | 缓存、配置项存储 |
LinkedHashMap | 维护插入或访问顺序 | 相比 HashMap 略慢 | LRU 缓存、按顺序遍历的配置项 |
TreeMap | 键自动排序,支持范围查询(O(log n)) | 插入/查找较慢(O(log n)) | 按键排序的字典 |
5. 结语
Java 集合框架提供了多样化的数据结构,适用于不同的开发需求。通过本文的综合介绍、对比说明和实战代码,你可以更好地理解每种集合的特点和用法,并在实际项目中选择合适的集合类型,提升代码效率和可维护性。