首页 / Java 入门教程 / Collections 工具类

Java 入门教程

Collections 工具类

本教程共 100 篇 · 第 80 篇 · 更新于 2026-08-05 · 约 5 分钟阅读

JavaJava 入门教程Collections排序工具类

80. Collections 工具类

本节目标:认识专门服务于集合的 Collections 工具类(注意和 Collection 接口的大小写差别),学完能用它排序、反转、查最值、生成不可变集合。

先分清两个长得很像的名字

Collection 是接口(单列集合的根),Collections 是个工具类,里面全是 static 方法,用来操作各种集合。大写小写的差别,初学者经常看花眼。

List<Integer> list = new ArrayList<>(List.of(3, 1, 2));
Collections.sort(list);          // 排序,注意是 Collections 不是 Collection
System.out.println(list);        // [1, 2, 3]
```bash

> [!NOTE]
> `Collections.sort(list)` 会原地修改原列表;如果你不想改原列表,可以先 `new ArrayList<>(list)` 拷贝一份再排。Java 8 起 `List` 接口自己也提供了 `list.sort(...)` 方法,效果一样,看个人习惯用哪个。

## 最常用的算法方法

这些方法是日常最高频的:

```java
Collections.sort(list);                 // 升序排序(元素需实现 Comparable)
Collections.sort(list, Comparator.reverseOrder()); // 降序
Collections.reverse(list);              // 反转顺序
Collections.shuffle(list);              // 随机打乱(洗牌)
Collections.fill(list, 0);              // 把所有元素填成同一个值
Integer max = Collections.max(list);    // 取最大
Integer min = Collections.min(list);    // 取最小
int idx = Collections.binarySearch(list, 2); // 二分查找,前提已排序,找不到返回负数

binarySearch 只有在列表已经排好序时才准,否则结果无意义。它比逐个遍历快得多,是「先排序、再查找」场景的标配。

拷贝和交换

List<Integer> src = List.of(1, 2, 3);
List<Integer> dst = new ArrayList<>(Arrays.asList(0, 0, 0));
Collections.copy(dst, src);   // 把 src 拷进 dst(dst 必须够长)
Collections.swap(list, 0, 2); // 交换下标 0 和 2 的元素
```bash

> [!WARNING]
> `Collections.copy(dst, src)` 要求目标列表长度不小于源列表,否则抛 `IndexOutOfBoundsException`。它不是「复制出一个新列表」,而是往已有列表里覆盖,别和 `new ArrayList<>(src)` 搞混。

## 生成特殊集合

`Collections` 还提供一批返回「特殊集合」的工厂方法,常用于写只读接口、测试桩:

```java
List<String> empty = Collections.emptyList();        // 空且不可变
Set<Integer> one = Collections.singleton(42);         // 只含一个元素,不可变
List<String> fixed = Collections.unmodifiableList(list); // 包装成只读,改会抛异常

unmodifiableList 返回的只是「视图」,底层还是那个 list,你改原来的 list,视图里也会变。它挡的是「通过视图去改」,不是「从源头改」。

Tip

想真正拿到一份不可变副本,优先用 Java 9 的 List.copyOf(list) / Set.copyOf / Map.copyOf,比 unmodifiableList(new ArrayList<>(...)) 写法更短更清晰。

synchronized 包装是历史兼容

Collections 有一组 synchronizedList / synchronizedMap / synchronizedSet,给集合套上同步锁,让它在多线程下「勉强安全」。

List<String> safe = Collections.synchronizedList(new ArrayList<>());
```bash

> [!WARNING]
> 这套同步包装只是历史兼容方案,性能一般,而且迭代时还得自己手动加锁才真安全。现代多线程场景请用 `java.util.concurrent` 里的 `ConcurrentHashMap`、`CopyOnWriteArrayList` 等专门实现,别拿 synchronized 包装凑合。

## sort 的两种传参

除了按自然顺序排,`Collections.sort` 还能接收 Comparator 自定义规则:

```java
List<String> words = new ArrayList<>(List.of("ccc", "a", "bb"));
Collections.sort(words, Comparator.comparing(String::length)); // 按长度排

其实 List 接口自己的 sort 方法也一样(words.sort(...))。两者选哪个都行,团队统一风格即可。Comparator 的写法详见第 82 章,这里先用起来感受一下。

max/min 也能自定义

max/min 默认按自然顺序取最值,也能传 Comparator:

List<User> users = ...;
User oldest = Collections.max(users, Comparator.comparingInt(User::age)); // 年龄最大
```bash

这让你「按某个字段取最大」变得一行搞定,比如从一堆用户里挑年龄最大的、从一堆商品里挑最贵的,不用自己写循环比大小。

## 二分查找的前提

`binarySearch` 要求列表「已经按相同比较规则排好序」。如果排序用了 Comparator,查找也要传同一个 Comparator,否则结果不可信。找不到时返回的是「插入点的负数」(不是简单的 -1),需要时再查文档细节,日常用得不多。

## 这些方法和 Stream 的关系

Java 8 起集合还能用 Stream(`list.stream().sorted()...`)做同样的事,功能更强。本章的 `Collections` 方法是「经典命令式」写法,先掌握它们,日后学 Stream 会轻松很多。两者不冲突,按场景挑——简单排序用 Collections,链式复杂处理用 Stream。

## 空集合和单元素集合的实战价值

`Collections.emptyList()` 看着没用,其实在写方法返回值时很香:当没数据要返回时,直接返回空集合而不是 `null`,调用方就不用判空,for-each 遍历空集合也不会报错。

```java
List<String> find(String key) {
    if (!store.containsKey(key)) {
        return Collections.emptyList(); // 比返回 null 友好得多
    }
    return store.get(key);
}

singleton(x) 则常用于把单个元素当集合传进去,比如 list.removeAll(Collections.singleton("x")) 一次性删掉所有等于 x 的元素,比手写循环简洁。

同步包装的真相

前面提过 synchronizedList 只是历史兼容。它确实让单操作线程安全,但「检查再操作」(如先 contains 再 add)这种复合动作仍然不安全,得你自己加锁。现代并发请用 java.util.concurrent 包,那里有真正为并发设计的实现。初学阶段你写的几乎都是单线程程序,了解有这回事即可,别急着往项目里塞同步包装。

小提醒:sort 是原地操作

Collections.sort 会直接改动你传进去的列表,而不是返回新列表。如果你不想破坏原数据,先拷贝:new ArrayList<>(list) 再排。很多人误以为 sort 返回排好序的新列表,结果原列表被改、返回值又没接,逻辑就乱了。记住它和 shuffle 一样都是原地修改,不会返回新列表。这个特性和 Arrays.sort 对数组的处理一致,牢记「排序即修改原集合」能让你少踩很多坑。

shuffle 的随机性

shuffle 用的是洗牌算法,每次结果不同,适合随机抽题、随机排序展示等场景。如果你想结果可复现(比如写测试),可以用带 Random 参数的重载 shuffle(list, random) 固定种子,这样每次跑出来顺序都一样,方便断言。

小结

Collections 是操作集合的工具类,提供排序、反转、洗牌、最值、二分查找、拷贝等算法方法,也能生成空集合、单元素集合和只读视图。它的大小写和 Collection 接口不同,别看错。下一章看遍历集合的底层机制——迭代器。