源本科技 | 码上会

Java Collections 工具类

2026/01/23
60
0

学习目标

  • 理解 java.util.Collections 工具类的作用与定位

  • 掌握常用集合工具方法的使用场景与实现效果

  • 区分 Collection(接口)Collections(工具类) 的本质差异

  • 熟悉常见集合类(如 ArrayList、HashMap、TreeSet 等)的基本特性

  • 能够在实际开发中灵活运用排序、搜索、同步、不可变视图等高级功能


Collection vs Collections

初学者常混淆这两个概念:

名称

类型

作用

Collection

接口

集合框架的根接口,定义了如 add()remove()size() 等通用操作

Collections

工具类(final class

提供大量 静态方法,用于操作或返回集合(如排序、查找、同步包装等)

记住:Collection 是“容器”,Collections 是“工具箱”


常见集合类概览

Java 集合框架提供了多种实现类,适用于不同场景:

列表(List)

  • ArrayList:基于动态数组,支持随机访问,非线程安全

  • LinkedList:基于双向链表,插入 / 删除快,随机访问慢

  • Vector:线程安全的动态数组(已不推荐,建议用 Collections.synchronizedList

集合(Set)

  • HashSet:基于哈希表,无序,查找快(内部使用 HashMap

  • LinkedHashSet:维护插入顺序的 HashSet

  • TreeSet:基于红黑树,元素自动排序(自然序或自定义比较器)

映射(Map)

  • HashMap:键值对存储,非线程安全,允许一个 null 键和多个 null

  • TreeMap:按键排序的 Map,基于红黑树

  • EnumMap:专为枚举类型设计的高性能 Map

队列与双端队列

  • PriorityQueue:优先级队列,按自然序或比较器排序

  • ArrayDeque:双端队列,支持栈和队列操作,性能优于 Stack

其他

  • Stack:继承自 Vector,实现 LIFO 栈(官方已不推荐,建议用 ArrayDeque


Collections 核心功能

Collections 类提供三大类实用方法:

1. 创建不可变集合

这些方法返回空或单元素的不可变集合,常用于初始化或防御性编程:

List<String> emptyList = Collections.emptyList();        // []
Set<Integer> emptySet = Collections.emptySet();          // {}
Map<String, String> emptyMap = Collections.emptyMap();   // {}

List<String> single = Collections.singletonList("OK");   // ["OK"]
Set<String> singleSet = Collections.singleton("YES");    // {"YES"}
Map<String, Integer> oneEntry = Collections.singletonMap("count", 1);

所有返回对象均为 不可修改,调用 add()put() 会抛出 UnsupportedOperationException


2. 集合操作与算法

添加元素

List<String> list = new ArrayList<>();
Collections.addAll(list, "A", "B", "C"); // 批量添加

排序

List<Integer> nums = Arrays.asList(3, 1, 4, 1, 5);
Collections.sort(nums); // [1, 1, 3, 4, 5]
Collections.sort(nums, Collections.reverseOrder()); // [5, 4, 3, 1, 1]

二分查找

必须先排序!

int index = Collections.binarySearch(sortedList, "target");
if (index >= 0) {
    System.out.println("Found at: " + index);
} else {
    int insertPos = -index - 1; // 应插入位置
}

复制

List<String> dest = new ArrayList<>(Arrays.asList("X", "Y", "Z", "W"));
List<String> src = Arrays.asList("A", "B", "C");
Collections.copy(dest, src); // dest becomes ["A", "B", "C", "W"]

目标列表长度必须 ≥ 源列表,否则抛出 IndexOutOfBoundsException

其他实用方法

int count = Collections.frequency(list, "Apple");     // 统计出现次数
boolean noCommon = Collections.disjoint(list1, list2); // 是否无交集
Collections.reverse(list);      // 反转
Collections.shuffle(list);      // 随机打乱
Collections.fill(list, "N/A");  // 全部替换为指定值
Collections.swap(list, 0, 1);   // 交换两个位置元素

3. 线程安全与类型安全

同步包装

线程安全

List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<Integer> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, Object> syncMap = Collections.synchronizedMap(new HashMap<>());

使用时仍需手动同步遍历操作:

synchronized (syncList) {
    for (String s : syncList) { ... }
}

不可修改视图

防御性编程

List<String> safeView = Collections.unmodifiableList(originalList);
// 任何修改操作都会抛出异常

类型安全检查

运行时校验

List<String> checkedList = Collections.checkedList(new ArrayList<>(), String.class);
checkedList.add("OK");   // OK
checkedList.add(123);    // 抛出 ClassCastException(即使编译通过)

实战示例

示例 1:批量添加元素

List<String> items = new ArrayList<>();
items.add("Shoes");
Collections.addAll(items, "Fruits", "Bat", "Ball");
// 结果: [Shoes, Fruits, Bat, Ball]

示例 2:升序与降序排序

Collections.sort(items); // 默认自然序
Collections.sort(items, Collections.reverseOrder()); // 逆序

示例 3:二分查找

Collections.sort(items);
int pos = Collections.binarySearch(items, "Horse"); // 返回索引 2
int notFound = Collections.binarySearch(items, "Dog"); // 返回 -2(表示应插入位置为 1)

示例 4:复制列表

List<String> dest = Arrays.asList("Shoes", "Toys", "Horse", "Tiger");
List<String> src = Arrays.asList("Bat", "Frog", "Lion");
Collections.copy(dest, src);
// dest 变为: [Bat, Frog, Lion, Tiger]

示例 5:判断两个集合是否无交集

boolean disjoint = Collections.disjoint(list1, list2); // true 表示无共同元素

特殊字段:预定义空集合

Collections 类提供三个静态字段,用于获取不可变的空集合实例

public static final List EMPTY_LIST;
public static final Set EMPTY_SET;
public static final Map EMPTY_MAP;

使用方式:

List<String> empty = Collections.EMPTY_LIST; // 不推荐(原始类型)
List<String> empty = Collections.emptyList(); // 推荐(泛型安全)

建议始终使用带泛型的方法(如 emptyList()),避免类型转换警告


最佳实践

  1. 优先使用不可变集合
    当集合内容确定后,用 unmodifiableXXX() 包装,防止意外修改。

  2. 谨慎使用同步包装
    synchronizedXXX() 仅提供基本线程安全,高并发场景建议使用 ConcurrentHashMapCopyOnWriteArrayList 等并发集合。

  3. 排序前务必确认有序性
    binarySearch() 要求列表已按相同规则排序,否则结果不可预测。

  4. 避免直接使用 Vector / Stack
    它们是遗留类,性能较差。用 ArrayList + Collections.synchronizedListArrayDeque 替代。

  5. 利用工具方法提升代码简洁性
    nCopies(5, "X") 生成 [X, X, X, X, X],比手写循环更清晰。


重点总结

  • Collections静态工具类,提供对集合的通用操作

  • 核心功能包括:排序、搜索、批量操作、同步包装、不可变视图、类型检查

  • 常见集合类各有适用场景:ArrayList(随机访问)、LinkedList(频繁插入)、HashSet(去重)、TreeSet(排序)等

  • 使用 binarySearch() 前必须确保列表已排序

  • 不可变集合和同步包装是构建健壮、线程安全程序的重要手段


思考题

  1. 为什么 Collections.synchronizedList(new ArrayList<>()) 在遍历时仍需要外部同步?请结合其内部实现说明。

  2. Collections.unmodifiableList() 返回的是“浅不可变”还是“深不可变”?如果列表中存储的是可变对象(如 Date),会发生什么问题?

  3. 假设你需要一个最多缓存 100 个最近使用的字符串的集合,并自动淘汰最旧的元素。你会选择哪种集合类?如何结合 Collections 工具类实现?