Collections工具类
Collections 是 Java 集合框架的工具类,提供排序、查找、反转、打乱、同步包装、不可修改视图、空集合、单元素集合等常用方法。
注意区分:
Collection是接口。Collections是工具类。
# 1. 常用方法总览
| 类别 | 方法 |
|---|---|
| 排序 | sort |
| 查找 | binarySearch |
| 最大最小 | max、min |
| 反转 | reverse |
| 打乱 | shuffle |
| 填充 | fill |
| 复制 | copy |
| 替换 | replaceAll |
| 同步包装 | synchronizedList、synchronizedMap |
| 只读包装 | unmodifiableList、unmodifiableMap |
| 空集合 | emptyList、emptySet、emptyMap |
| 单元素集合 | singletonList、singleton、singletonMap |
# 2. 排序
List<Integer> numbers = new ArrayList<>(List.of(3, 1, 2));
Collections.sort(numbers);
System.out.println(numbers); // [1, 2, 3]
自定义排序:
List<User> users = new ArrayList<>();
users.sort(Comparator.comparing(User::getAge));
Collections.sort(list) 和 list.sort(comparator) 都可以使用。现代代码中常直接使用 list.sort。
# 3. 二分查找
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4));
int index = Collections.binarySearch(numbers, 3);
前提:列表必须已经按同一规则排序。
排序规则
│
▼
binarySearch 使用同一规则
│
▼
结果才可靠
错误示例:
List<Integer> numbers = List.of(3, 1, 2);
Collections.binarySearch(numbers, 2); // 结果不可依赖
如果使用自定义比较器排序,查找也要传同一个比较器。
# 4. max 与 min
Integer max = Collections.max(numbers);
Integer min = Collections.min(numbers);
自定义规则:
User oldest = Collections.max(users, Comparator.comparing(User::getAge));
空集合调用 max/min 会抛 NoSuchElementException,调用前要判断或使用 Optional 风格处理。
# 5. reverse、shuffle、rotate
反转:
Collections.reverse(list);
打乱:
Collections.shuffle(list);
旋转:
Collections.rotate(list, 2);
示意:
[A, B, C, D]
rotate 1
[D, A, B, C]
这些方法会直接修改传入的列表。
# 6. fill、copy、replaceAll
填充:
Collections.fill(list, "N/A");
复制:
List<String> src = List.of("A", "B");
List<String> dest = new ArrayList<>(Arrays.asList("", ""));
Collections.copy(dest, src);
注意:dest 必须已有足够长度。copy 不会自动扩容到所需 size。
替换:
Collections.replaceAll(list, "old", "new");
# 7. synchronized 包装
List<String> list = Collections.synchronizedList(new ArrayList<>());
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
它通过包装对象给方法加同步。
调用 wrapper.add
│
▼
synchronized(mutex)
│
▼
调用底层 list.add
遍历时仍需要手动同步:
List<String> list = Collections.synchronizedList(new ArrayList<>());
synchronized (list) {
for (String value : list) {
System.out.println(value);
}
}
同步包装适合简单场景。高并发场景应优先考虑并发集合。
# 8. unmodifiable 包装
List<String> source = new ArrayList<>();
source.add("A");
List<String> view = Collections.unmodifiableList(source);
通过 view 修改会抛异常:
view.add("B"); // UnsupportedOperationException
但底层集合变化,视图也会变化:
source.add("B");
System.out.println(view); // [A, B]
结构:
source ArrayList
▲
│ 包装
unmodifiable view
如果需要不可变副本,使用:
List<String> copy = List.copyOf(source);
# 9. empty 与 singleton
空集合:
return Collections.emptyList();
单元素集合:
return Collections.singletonList(user);
好处:
- 避免返回
null。 - 避免重复创建无意义空集合。
- 表达不可修改语义。
返回集合时,通常推荐返回空集合而不是 null:
public List<User> queryUsers() {
if (noResult) {
return Collections.emptyList();
}
return users;
}
# 10. checked 包装
Collections.checkedList 可以在运行期检查元素类型。
List raw = new ArrayList();
List<String> checked = Collections.checkedList(raw, String.class);
checked.add("A");
raw.add(123);
这种方法主要用于老代码和原始类型混用场景,现代泛型代码中较少直接使用。
# 11. Collections 与 List.of
| 写法 | 特点 |
|---|---|
Collections.emptyList() | 不可修改空列表 |
Collections.singletonList(x) | 不可修改单元素列表,允许元素为 null |
Collections.unmodifiableList(list) | 只读视图,底层可变 |
List.of(...) | 不可变集合,不允许 null |
List.copyOf(list) | 创建不可变副本,不允许 null |
示例:
List<String> list = List.of("A", "B");
List.of 创建的集合不能修改:
list.add("C"); // UnsupportedOperationException
# 12. 常见误区
# 12.1 unmodifiable 不是深不可变
List<User> users = Collections.unmodifiableList(source);
users.get(0).setName("Tom"); // 仍然可能修改对象内部状态
它只限制集合结构修改,不限制元素对象自身可变性。
# 12.2 synchronized 包装不等于所有操作原子
if (!list.contains(value)) {
list.add(value);
}
这两个方法分别同步,但组合操作不是原子的。需要把整个组合包进同步块。
# 12.3 binarySearch 前必须排序
二分查找依赖有序性,无序列表查找结果不可依赖。
# Tips 快问快答
Q:Collection 和 Collections 有什么区别?
A:Collection 是接口,Collections 是工具类。
Q:Collections.sort 会修改原列表吗?
A:会,它是原地排序。
Q:binarySearch 前必须做什么?
A:必须按同一比较规则排序。
Q:Collections.copy 会自动扩容目标 List 吗?
A:不会,目标列表必须已有足够 size。
Q:unmodifiableList 是不可变集合吗?
A:它是只读视图,底层集合变化会反映到视图。
Q:List.copyOf 和 unmodifiableList 有什么区别?
A:copyOf 创建不可变副本,unmodifiableList 包装原集合视图。
Q:同步包装集合遍历时安全吗? A:需要手动在包装对象上同步遍历。
Q:为什么推荐返回空集合而不是 null? A:调用方可以直接遍历,减少空指针判断。
Q:List.of 能放 null 吗?
A:不能,会抛 NullPointerException。
Q:max/min 空集合会怎样?
A:会抛 NoSuchElementException。