Collections工具类

Collections是什么

Collections(注意有个s)是一个工具类,全是静态方法,专门用来操作集合

就像 Arrays 是操作数组的工具类一样,Collections 是操作 Collection体系 的工具类

⚠️ 别跟 Collection(没有s,是接口)搞混了!

名称 类型 作用
Collection 接口 集合的顶层接口,定义了add/remove/contains等方法
Collections 工具类 提供排序、查找、同步等静态工具方法

排序相关:sort / reverse / shuffle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testSortAndShuffle() {
List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6));

// 排序(默认升序)
Collections.sort(list);
System.out.println("升序:" + list); // [1, 1, 2, 3, 4, 5, 6, 9]

// 降序:传入反向比较器
Collections.sort(list, Collections.reverseOrder());
System.out.println("降序:" + list); // [9, 6, 5, 4, 3, 2, 1, 1]

// 反转(不是排序,单纯把顺序倒过来)
Collections.reverse(list);
System.out.println("反转:" + list); // [1, 1, 2, 3, 4, 5, 6, 9]

// 洗牌(随机打乱顺序)
Collections.shuffle(list);
System.out.println("洗牌:" + list); // 每次结果不同,如 [4, 1, 9, 2, 6, 1, 3, 5]
}

自定义对象排序

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testCustomSort() {
List<String> names = new ArrayList<>(Arrays.asList("张三", "李四", "王五", "赵六"));

// 按字符串长度排序
Collections.sort(names, (a, b) -> a.length() - b.length());
System.out.println(names);

// Java8更优雅的写法
names.sort(Comparator.comparingInt(String::length));
System.out.println(names);
}

查找相关:max / min / frequency

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void testSearchMethods() {
List<Integer> list = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);

// 最大值
System.out.println("最大值:" + Collections.max(list)); // 9

// 最小值
System.out.println("最小值:" + Collections.min(list)); // 1

// 某个元素出现的次数
System.out.println("1出现了几次:" + Collections.frequency(list, 1)); // 2

// 二分查找(前提:list必须已排序!)
List<Integer> sorted = new ArrayList<>(list);
Collections.sort(sorted);
int index = Collections.binarySearch(sorted, 5);
System.out.println("5的下标:" + index); // 5
}

不可修改集合:unmodifiableList / unmodifiableMap

把一个普通集合”冻住”,变成只读的,任何修改操作都抛 UnsupportedOperationException

适合用在返回内部数据时,防止外部代码乱改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test
public void testUnmodifiable() {
List<String> original = new ArrayList<>(Arrays.asList("A", "B", "C"));

// 包装成不可修改的List
List<String> readOnly = Collections.unmodifiableList(original);

System.out.println(readOnly.get(0)); // A,读取没问题

// readOnly.add("D"); // ❌ UnsupportedOperationException
// readOnly.set(0, "X"); // ❌ UnsupportedOperationException

// ⚠️ 注意:修改原始List,readOnly也会变!
original.add("D");
System.out.println(readOnly); // [A, B, C, D]
// 所以如果真想完全不可变,别保留original的引用

// Map也一样
Map<String, Integer> map = new HashMap<>();
map.put("key", 1);
Map<String, Integer> readOnlyMap = Collections.unmodifiableMap(map);
// readOnlyMap.put("key2", 2); // ❌

// Java9以后更简洁的写法:
// List<String> immutable = List.of("A", "B", "C");
// Map<String, Integer> immutableMap = Map.of("key", 1);
}

线程安全包装:synchronizedList / synchronizedMap

给普通集合套上 synchronized 锁,变成线程安全版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testSynchronized() {
// 把普通ArrayList变成线程安全的
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
syncList.add("A");
syncList.add("B");

// 把普通HashMap变成线程安全的
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
syncMap.put("key", 1);

// ⚠️ 遍历时还是要手动加锁!
synchronized (syncList) {
for (String s : syncList) {
System.out.println(s);
}
}
}

⚠️ 实际开发中更推荐用 java.util.concurrent 包下的并发集合:

CopyOnWriteArrayList 替代 synchronizedList

ConcurrentHashMap 替代 synchronizedMap(详见 Map体系

特殊集合:emptyList / singletonList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testSpecialCollections() {
// 空集合(不可修改)
List<String> empty = Collections.emptyList();
System.out.println(empty); // []
System.out.println(empty.size()); // 0
// empty.add("A"); // ❌ UnsupportedOperationException

// 用途:方法返回空集合时,用这个比 new ArrayList<>() 省内存
// 例如:return results.isEmpty() ? Collections.emptyList() : results;

// 只有一个元素的集合(不可修改)
List<String> single = Collections.singletonList("唯一元素");
System.out.println(single); // [唯一元素]
// single.add("第二个"); // ❌

// emptyMap / emptySet 也一样
Map<String, Integer> emptyMap = Collections.emptyMap();
Set<String> emptySet = Collections.emptySet();
}

其他实用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Test
public void testOtherMethods() {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));

// swap:交换两个位置的元素
Collections.swap(list, 0, 4);
System.out.println("交换后:" + list); // [E, B, C, D, A]

// fill:把所有元素替换成指定值
Collections.fill(list, "X");
System.out.println("填充后:" + list); // [X, X, X, X, X]

// nCopies:创建n个相同元素的不可修改List
List<String> copies = Collections.nCopies(5, "Hello");
System.out.println(copies); // [Hello, Hello, Hello, Hello, Hello]

// disjoint:判断两个集合是否没有交集
List<Integer> listA = Arrays.asList(1, 2, 3);
List<Integer> listB = Arrays.asList(4, 5, 6);
List<Integer> listC = Arrays.asList(3, 4, 5);
System.out.println(Collections.disjoint(listA, listB)); // true,无交集
System.out.println(Collections.disjoint(listA, listC)); // false,有交集(3)

// replaceAll:把所有旧值替换成新值
List<String> colors = new ArrayList<>(Arrays.asList("红", "绿", "红", "蓝"));
Collections.replaceAll(colors, "红", "黄");
System.out.println(colors); // [黄, 绿, 黄, 蓝]
}

常用方法速查表

方法 作用 注意点
sort(list) 升序排序 可传Comparator自定义
reverse(list) 反转顺序 不是排序,单纯倒过来
shuffle(list) 随机打乱 洗牌算法
max(collection) 最大值
min(collection) 最小值
frequency(collection, obj) 出现次数
binarySearch(list, key) 二分查找 list必须已排序
unmodifiableList(list) 不可修改包装 原list改了它也变
synchronizedList(list) 线程安全包装 遍历仍需手动同步
emptyList() 空集合 不可修改
singletonList(obj) 单元素集合 不可修改
swap(list, i, j) 交换两个位置
fill(list, obj) 全部替换
disjoint(c1, c2) 是否无交集

常见坑

坑1:binarySearch之前忘了排序

Collections.binarySearch() 要求List必须是已排序的,否则结果不可预测

坑2:以为unmodifiable是深拷贝

unmodifiableList(original) 只是个包装,修改original还是会影响到它

想真正不可变,用 List.copyOf()(Java10+)或手动深拷贝

坑3:synchronizedList遍历不加锁

虽然单个操作(add/get)是线程安全的,但遍历时还是可能被其他线程修改

遍历必须手动 synchronized(syncList) { ... }


上一章 目录 下一章
Map体系 java基础 泛型