Java 集合框架概览
List/Set/Map 的职责分工、常用实现选型、迭代与并发边界入口。
#concept
#growing
#dev
#java
[!info] related notes
Java 集合框架概览
这个概念为什么出现
真实业务很少只操作单个变量:购物车行、SKU 索引、去重标签、配置字典都需要集合。Java 集合框架用接口 + 实现分离“契约”与“数据结构选择”。
[!abstract] 一句话理解
List有序可重复,Set去重,Map键值索引;先选接口语义,再选ArrayList/HashSet/HashMap等实现,并遵守元素 equals/hashCode 契约。
最小可运行示例
场景:购物车维护商品行与优惠标签
import java.util.*;
public class CartCollections {
public static void main(String[] args) {
List<String> lines = new ArrayList<>();
lines.add("SKU-1");
lines.add("SKU-1"); // List 允许重复
System.out.println("lines=" + lines.size());
Set<String> tags = new HashSet<>();
tags.add("promo");
tags.add("promo"); // Set 去重
System.out.println("tags=" + tags.size());
Map<String, Integer> stock = new HashMap<>();
stock.put("SKU-1", 3);
stock.put("SKU-2", 0);
System.out.println("SKU-1=" + stock.get("SKU-1"));
System.out.println("missing=" + stock.get("SKU-9")); // null
}
}
建议运行:
javac CartCollections.java && java CartCollections
期望输出:
lines=2
tags=1
SKU-1=3
missing=null
结合场景再看三个关注点
- 接口类型声明变量(
List/Map),实现可替换。 - Map 未命中返回 null;允许 null 值的映射也可返回 null。
getOrDefault只在键不存在时返回默认值,不能替换已映射的 null。 - HashSet 去重依赖 equals/hashCode;TreeSet/TreeMap 以自然顺序或比较器的
compare == 0判断元素/键重复。排序需与 equals 一致才能遵守通常的 Set/Map 契约。
核心概念与准确模型
1. 核心接口
| 接口 | 语义 |
|---|---|
Collection | 单列集合根 |
List | 有序、下标、可重复 |
Set | 无重复 |
Map | 键值,键唯一;不继承 Collection |
Queue/Deque | 队列/双端 |
2. 常用实现选型
| 需求 | 常见选择 |
|---|---|
| 随机访问列表 | ArrayList |
| 队列/双端队列的头尾操作 | 通常先考虑 ArrayDeque(不允许 null) |
| 去重无序 | HashSet |
| 排序去重 | TreeSet |
| 键值检索 | HashMap |
| 键排序 | TreeMap |
| 保持插入序 | LinkedHashMap |
3. 迭代与修改
- fail-fast 迭代器在检测到结构修改时可能抛
ConcurrentModificationException,属于尽力检测,不能依赖它保证并发安全。 - 若迭代器支持,可用其
remove删除当前元素;也可结束遍历后统一删除。并发集合的迭代契约另见并发集合篇。
4. 不可修改集合与视图
List.of/Map.of及相应copyOf不允许修改集合结构,也拒绝 null;元素对象仍可能可变。copyOf不随源集合后续的结构变化而改变。Collections.unmodifiableList是只读视图,底层列表的修改仍会反映出来。Arrays.asList是数组支持的定长列表,允许set,不支持增删;列表与数组共享元素槽位。
边界情况与反直觉行为
HashMap允许一个 null 键和 null 值,这是文档约定;Hashtable/ConcurrentHashMap均不允许 null 键或值。TreeMap可使用键的自然顺序或显式比较器;显式比较器下键不必实现 Comparable。自然顺序拒绝 null 键,比较器可自行支持 null。- 集合不是线程安全默认——见并发集合篇。
常见误区
[!warning] 常见误区:返回 null List 返回空列表,避免调用方 NPE。
工程实践
- 方法参数尽量用接口类型。
- 暴露集合前区分只读视图和不可修改快照;两者都不自动深拷贝可变元素。
- 大键对象注意 hash 成本。
- 选型先语义后性能,性能靠测量。
本节总结
- List/Set/Map 语义三分
- 实现按访问模式选
- equals/hashCode 与并发边界决定正确性
自测题
- 何时用 Set 而不是 List?
- 为什么变量写成
List<String> x = new ArrayList<>()?
参考答案
- 需要去重/成员测试且不关心重复插入语义时。
- 依赖接口契约,便于替换实现与测试。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Collections Framework Overview | 官方 | 框架总览 |
| List / Map API | API | 接口契约 |