Java 完全指南 / 14 - 集合框架:List、Set、Map、Queue、Iterator
14 - 集合框架:List、Set、Map、Queue、Iterator
集合框架全景
Iterable
├── Collection
│ ├── List(有序,可重复)
│ │ ├── ArrayList
│ │ ├── LinkedList
│ │ └── Vector / Stack
│ ├── Set(无序,不重复)
│ │ ├── HashSet
│ │ ├── LinkedHashSet
│ │ └── TreeSet
│ └── Queue(队列)
│ ├── LinkedList
│ ├── PriorityQueue
│ └── ArrayDeque
└── Map(键值对)
├── HashMap
├── LinkedHashMap
├── TreeMap
├── Hashtable
└── ConcurrentHashMap
List — 有序可重复
ArrayList
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
// 创建
List<String> list = new ArrayList<>();
List<String> fixed = List.of("A", "B", "C"); // 不可变
List<String> copied = List.copyOf(fixed); // 不可变副本
// 添加
list.add("张三");
list.add("李四");
list.add(0, "王五"); // 指定位置插入
list.addAll(List.of("赵六", "钱七"));
// 访问
System.out.println(list.get(0)); // 王五
System.out.println(list.size()); // 5
System.out.println(list.indexOf("李四")); // 2
System.out.println(list.contains("张三")); // true
// 修改
list.set(0, "老王");
// 删除
list.remove("李四"); // 按对象删除
list.remove(0); // 按索引删除
list.removeIf(s -> s.startsWith("赵")); // 条件删除
// 排序
list.sort(Comparator.naturalOrder());
list.sort(Comparator.reverseOrder());
list.sort(Comparator.comparingInt(String::length));
// 遍历
for (String s : list) System.out.println(s);
list.forEach(System.out::println);
// 转换
String[] arr = list.toArray(new String[0]);
List<String> sub = list.subList(0, 2); // 视图,非副本
}
}
ArrayList vs LinkedList
| 维度 | ArrayList | LinkedList |
|---|---|---|
| 底层 | 动态数组 | 双向链表 |
| 随机访问 | O(1) | O(n) |
| 头部插入/删除 | O(n) | O(1) |
| 尾部插入 | O(1) | O(1) |
| 内存 | 紧凑 | 每个节点额外开销 |
| 推荐场景 | 通用首选 | 频繁头部操作 |
💡 绝大多数场景使用
ArrayList,它是性能最好的通用 List 实现。
Set — 无序不重复
import java.util.*;
public class SetDemo {
public static void main(String[] args) {
// HashSet —— 基于 HashMap,O(1) 操作
Set<String> hashSet = new HashSet<>();
hashSet.add("张三");
hashSet.add("李四");
hashSet.add("张三"); // 重复,不添加
System.out.println(hashSet.size()); // 2
System.out.println(hashSet.contains("张三")); // true
// LinkedHashSet —— 保持插入顺序
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("C"); linkedSet.add("A"); linkedSet.add("B");
System.out.println(linkedSet); // [C, A, B]
// TreeSet —— 自然排序,红黑树实现
Set<String> treeSet = new TreeSet<>();
treeSet.add("C"); treeSet.add("A"); treeSet.add("B");
System.out.println(treeSet); // [A, B, C]
// 集合运算
Set<Integer> a = Set.of(1, 2, 3, 4);
Set<Integer> b = Set.of(3, 4, 5, 6);
// 并集
Set<Integer> union = new HashSet<>(a);
union.addAll(b);
System.out.println("并集: " + union); // [1, 2, 3, 4, 5, 6]
// 交集
Set<Integer> intersection = new HashSet<>(a);
intersection.retainAll(b);
System.out.println("交集: " + intersection); // [3, 4]
// 差集
Set<Integer> diff = new HashSet<>(a);
diff.removeAll(b);
System.out.println("差集: " + diff); // [1, 2]
}
}
Map — 键值对
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
// 创建
Map<String, Integer> scores = new HashMap<>();
scores.put("张三", 90);
scores.put("李四", 85);
scores.put("王五", 92);
// 访问
int zhangScore = scores.get("张三"); // 90
int defaultScore = scores.getOrDefault("赵六", 0); // 0
System.out.println("包含张三: " + scores.containsKey("张三"));
System.out.println("包含90: " + scores.containsValue(90));
// 遍历
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
scores.forEach((k, v) -> System.out.println(k + " -> " + v));
// Java 8 新方法
scores.putIfAbsent("赵六", 88); // 不存在才添加
scores.merge("张三", 5, Integer::sum); // 张三: 90+5=95
scores.compute("李四", (k, v) -> v == null ? 0 : v + 10); // 李四: 95
// 排序
Map<String, Integer> sorted = new TreeMap<>(scores); // 按 key 排序
scores.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
// 不可变 Map
Map<String, Integer> immutable = Map.of("A", 1, "B", 2, "C", 3);
Map<String, Integer> copied = Map.copyOf(scores);
}
}
Map 实现对比
| 实现 | 有序 | 线程安全 | null 键 | 适用场景 |
|---|---|---|---|---|
| HashMap | ❌ | ❌ | ✅ | 通用首选 |
| LinkedHashMap | 插入序 | ❌ | ✅ | 需要保持插入顺序 |
| TreeMap | 排序序 | ❌ | ❌ | 需要 key 排序 |
| Hashtable | ❌ | ✅ | ❌ | 遗留,不推荐 |
| ConcurrentHashMap | ❌ | ✅ | ❌ | 并发场景首选 |
Queue & Deque
import java.util.*;
public class QueueDemo {
public static void main(String[] args) {
// ArrayDeque —— 双端队列(推荐作栈和队列)
Deque<String> deque = new ArrayDeque<>();
deque.offerFirst("A"); // 头部入队
deque.offerLast("B"); // 尾部入队
deque.offerLast("C");
System.out.println(deque.peekFirst()); // A
System.out.println(deque.peekLast()); // C
deque.pollFirst(); // 移除 A
// 用作栈
Deque<String> stack = new ArrayDeque<>();
stack.push("第一层");
stack.push("第二层");
stack.push("第三层");
System.out.println(stack.pop()); // 第三层(LIFO)
System.out.println(stack.peek()); // 第二层
// PriorityQueue —— 优先队列(最小堆)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(5); minHeap.offer(1); minHeap.offer(3);
System.out.println(minHeap.poll()); // 1(最小值先出)
System.out.println(minHeap.poll()); // 3
// 最大堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
maxHeap.offer(5); maxHeap.offer(1); maxHeap.offer(3);
System.out.println(maxHeap.poll()); // 5(最大值先出)
}
}
不可变集合(JDK 9+)
import java.util.*;
public class ImmutableCollections {
public static void main(String[] args) {
// List 不可变
List<String> list = List.of("A", "B", "C");
// list.add("D"); // ❌ UnsupportedOperationException
// Set 不可变
Set<Integer> set = Set.of(1, 2, 3);
// Map 不可变(最多 10 个键值对)
Map<String, Integer> map = Map.of("one", 1, "two", 2, "three", 3);
// 更多键值对用 Map.ofEntries
Map<String, Integer> bigMap = Map.ofEntries(
Map.entry("A", 1),
Map.entry("B", 2),
Map.entry("C", 3)
);
// 从可变集合创建不可变副本
List<String> mutable = new ArrayList<>(list);
List<String> immutable = List.copyOf(mutable);
}
}
集合选型指南
| 需求 | 推荐 | 说明 |
|---|---|---|
| 有序列表,按索引访问 | ArrayList | 通用首选 |
| 频繁头部增删 | LinkedList | 链表结构 |
| 不重复集合 | HashSet | 去重首选 |
| 不重复且排序 | TreeSet | 红黑树 |
| 键值对 | HashMap | 通用首选 |
| 键值对且排序 | TreeMap | 按 key 排序 |
| 并发安全 Map | ConcurrentHashMap | 分段锁 |
| FIFO 队列 | ArrayDeque | 双端队列 |
| 优先级队列 | PriorityQueue | 堆结构 |
⚠️ 注意事项
- 线程不安全 —
ArrayList、HashMap非线程安全,并发环境用ConcurrentHashMap或Collections.synchronizedList()。 - ConcurrentModificationException — 遍历时不要直接
remove(),用Iterator.remove()或removeIf()。 - HashMap 的 key 需要重写
equals和hashCode— 否则无法正确去重。 Arrays.asList()返回的列表不可增删 — 底层仍是数组。
💡 技巧
Map 计数器:
Map<String, Integer> counter = new HashMap<>(); words.forEach(w -> counter.merge(w, 1, Integer::sum));Map computeIfAbsent:
Map<String, List<String>> groups = new HashMap<>(); items.forEach(item -> groups.computeIfAbsent(item.getCategory(), k -> new ArrayList<>()).add(item));List 转 Map:
Map<Long, User> userMap = users.stream() .collect(Collectors.toMap(User::getId, u -> u));
🏢 业务场景
- 缓存:
HashMap/ConcurrentHashMap实现本地缓存。 - 排行榜:
TreeMap或PriorityQueue实现 Top N。 - 分组统计:
Map<String, List<T>>按字段分组。 - BFS/DFS:
Queue+Set实现图的遍历。