Java 集合工具类(java.util.Collections
)详解
java.util.Collections
是 Java 提供的集合操作工具类,包含大量静态方法,用于操作或返回集合(如排序、查找、同步控制等)。它弥补了集合实现类自身方法的不足,简化了常见的集合操作。本文将详细讲解其核心功能和常用方法,结合代码示例说明用法。
一、Collections
工具类的特点
- 静态方法:所有方法均为
static
,无需创建实例,直接通过类名调用(Collections.方法名()
)。 - 通用性:适用于
Collection
框架中的各种集合(List
、Set
、Map
等)。 - 功能丰富:涵盖排序、查找、替换、同步化、不可修改化等操作。
二、核心功能与常用方法
1. 排序操作(针对 List
)
Collections
提供了多种排序方法,仅适用于 List
(因 Set
和 Map
的排序依赖其实现类自身特性,如 TreeSet
、TreeMap
)。
方法声明 | 功能描述 |
---|---|
static <T extends Comparable<? super T>> void sort(List<T> list) | 对 List 按自然顺序排序(元素需实现 Comparable ) |
static <T> void sort(List<T> list, Comparator<? super T> c) | 按自定义比较器排序 |
static void reverse(List<?> list) | 反转 List 中元素的顺序 |
static void shuffle(List<?> list) | 随机打乱 List 中元素的顺序(洗牌) |
static <T> void swap(List<?> list, int i, int j) | 交换 List 中指定索引 i 和 j 的元素 |
代码示例:排序操作
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CollectionsSortDemo {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
System.out.println("初始列表:" + numbers); // [3, 1, 2]
// 1. 自然排序(从小到大)
Collections.sort(numbers);
System.out.println("自然排序后:" + numbers); // [1, 2, 3]
// 2. 自定义比较器(从大到小)
Collections.sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; // 反转比较顺序
}
});
System.out.println("自定义排序后:" + numbers); // [3, 2, 1]
// 3. 反转列表
Collections.reverse(numbers);
System.out.println("反转后:" + numbers); // [1, 2, 3]
// 4. 随机打乱(每次结果不同)
Collections.shuffle(numbers);
System.out.println("打乱后:" + numbers); // 例如:[2, 3, 1]
// 5. 交换元素(索引0和2)
Collections.swap(numbers, 0, 2);
System.out.println("交换后:" + numbers); // 例如:[1, 3, 2]
}
}
2. 查找与替换(针对 List
)
提供在 List
中查找元素、替换元素的方法,部分方法依赖排序(如二分查找)。
方法声明 | 功能描述 |
---|---|
static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) | 二分查找指定元素的索引(需先排序,未找到返回负数) |
static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) | 基于比较器的二分查找(需先按该比较器排序) |
static <T> int indexOfSubList(List<?> source, List<?> target) | 查找子列表 target 在 source 中首次出现的索引(未找到返回 -1 ) |
static <T> int lastIndexOfSubList(List<?> source, List<?> target) | 查找子列表 target 在 source 中最后出现的索引 |
static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) | 将 list 中所有 oldVal 替换为 newVal (返回是否有替换) |
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) | 返回集合中自然顺序最大的元素 |
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) | 返回集合中比较器定义的最大元素 |
static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) | 返回集合中自然顺序最小的元素 |
static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) | 返回集合中比较器定义的最小元素 |
代码示例:查找与替换
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsSearchDemo {
public static void main(String[] args) {
// 1. 二分查找(需先排序)
List<Integer> nums = new ArrayList<>();
nums.add(10);
nums.add(20);
nums.add(30);
nums.add(40);
Collections.sort(nums); // 先排序(必须!)
int index = Collections.binarySearch(nums, 30);
System.out.println("30的索引:" + index); // 2(找到)
int index2 = Collections.binarySearch(nums, 25);
System.out.println("25的索引(未找到):" + index2); // -3(负数表示插入点)
// 2. 查找子列表
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("B");
list.add("C");
List<String> subList = new ArrayList<>();
subList.add("B");
subList.add("C");
int first = Collections.indexOfSubList(list, subList);
int last = Collections.lastIndexOfSubList(list, subList);
System.out.println("子列表首次出现索引:" + first); // 1
System.out.println("子列表最后出现索引:" + last); // 3
// 3. 替换元素
boolean replaced = Collections.replaceAll(list, "B", "X");
System.out.println("是否替换成功:" + replaced); // true
System.out.println("替换后列表:" + list); // [A, X, C, X, C]
// 4. 查找最大/最小值
List<Integer> maxMinList = new ArrayList<>();
maxMinList.add(5);
maxMinList.add(2);
maxMinList.add(8);
int max = Collections.max(maxMinList);
int min = Collections.min(maxMinList);
System.out.println("最大值:" + max); // 8
System.out.println("最小值:" + min); // 2
}
}
3. 同步控制(返回线程安全集合)
Java 集合框架中的大部分实现类(如 ArrayList
、HashMap
)都是非线程安全的(多线程并发修改可能导致异常)。Collections
提供了将非线程安全集合转换为线程安全集合的方法,内部通过加锁实现同步。
方法声明 | 功能描述 |
---|---|
static <T> Collection<T> synchronizedCollection(Collection<T> c) | 返回线程安全的 Collection |
static <T> List<T> synchronizedList(List<T> list) | 返回线程安全的 List |
static <T> Set<T> synchronizedSet(Set<T> s) | 返回线程安全的 Set |
static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) | 返回线程安全的 SortedSet |
static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) | 返回线程安全的 Map |
static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) | 返回线程安全的 SortedMap |
代码示例:线程安全集合
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class CollectionsSynchronizedDemo {
public static void main(String[] args) {
// 非线程安全的List
List<String> unsafeList = new ArrayList<>();
// 转换为线程安全的List
List<String> safeList = Collections.synchronizedList(unsafeList);
// 非线程安全的Map
Map<String, Integer> unsafeMap = new HashMap<>();
// 转换为线程安全的Map
Map<String, Integer> safeMap = Collections.synchronizedMap(unsafeMap);
// 线程安全集合的使用方式与原集合一致
safeList.add("Java");
safeMap.put("Score", 90);
System.out.println("安全List:" + safeList); // [Java]
System.out.println("安全Map:" + safeMap); // {Score=90}
}
}
注意:
- 线程安全集合仅保证单个方法的原子性,复合操作(如“检查再更新”)仍需手动加锁。
- 性能较低,高并发场景推荐使用
java.util.concurrent
包下的并发集合(如ConcurrentHashMap
、CopyOnWriteArrayList
)。
4. 不可修改集合(只读集合)
通过 Collections
可以创建不可修改的集合(只读),任何修改操作(如 add
、remove
、put
)都会抛出 UnsupportedOperationException
,用于保护集合数据不被篡改。
方法声明 | 功能描述 |
---|---|
static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) | 返回不可修改的 Collection |
static <T> List<T> unmodifiableList(List<? extends T> list) | 返回不可修改的 List |
static <T> Set<T> unmodifiableSet(Set<? extends T> s) | 返回不可修改的 Set |
static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s) | 返回不可修改的 SortedSet |
static <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m) | 返回不可修改的 Map |
static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,? extends V> m) | 返回不可修改的 SortedMap |
代码示例:不可修改集合
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class CollectionsUnmodifiableDemo {
public static void main(String[] args) {
// 原始可修改集合
List<String> mutableList = new ArrayList<>();
mutableList.add("A");
mutableList.add("B");
// 创建不可修改的List(只读)
List<String> unmodList = Collections.unmodifiableList(mutableList);
System.out.println("只读List:" + unmodList); // [A, B]
// 尝试修改只读集合(抛出异常)
try {
unmodList.add("C"); // 编译通过,运行时抛异常
} catch (UnsupportedOperationException e) {
System.out.println("错误:" + e.getMessage()); // 不支持的操作
}
// 原始集合修改,只读集合也会变化(只读集合是原始集合的视图)
mutableList.add("C");
System.out.println("原始集合修改后,只读List:" + unmodList); // [A, B, C]
// 不可修改的Map示例
Map<String, Integer> mutableMap = new HashMap<>();
mutableMap.put("One", 1);
Map<String, Integer> unmodMap = Collections.unmodifiableMap(mutableMap);
try {
unmodMap.put("Two", 2); // 抛异常
} catch (UnsupportedOperationException e) {
System.out.println("Map修改错误:" + e.getMessage());
}
}
}
注意:
- 不可修改集合是原始集合的视图,若原始集合被修改,只读集合也会同步变化。
- 若需完全独立的只读集合,需先创建副本(如
new ArrayList<>(original)
),再转为只读。
5. 空集合(空的不可修改集合)
Collections
提供了预定义的空集合(空列表、空集、空映射),用于避免返回 null
(更安全,减少 NullPointerException
)。
方法声明 | 功能描述 |
---|---|
static <T> List<T> emptyList() | 返回空的不可修改 List (泛型) |
static <T> Set<T> emptySet() | 返回空的不可修改 Set (泛型) |
static <K,V> Map<K,V> emptyMap() | 返回空的不可修改 Map (泛型) |
代码示例:空集合
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.Collections;
public class CollectionsEmptyDemo {
public static void main(String[] args) {
// 获取空集合(不可修改)
List<String> emptyList = Collections.emptyList();
Set<Integer> emptySet = Collections.emptySet();
Map<String, Double> emptyMap = Collections.emptyMap();
System.out.println("空List大小:" + emptyList.size()); // 0
System.out.println("空Set是否为空:" + emptySet.isEmpty()); // true
// 尝试修改空集合(抛异常)
try {
emptyList.add("test");
} catch (UnsupportedOperationException e) {
System.out.println("空集合修改错误:" + e.getMessage());
}
// 实际应用:方法返回空集合而非null
List<String> result = getData();
System.out.println("方法返回的集合大小:" + result.size()); // 0(避免NPE)
}
// 模拟查询数据,无结果时返回空集合而非null
public static List<String> getData() {
// 假设查询无结果
return Collections.emptyList(); // 比return null更安全
}
}
6. 其他实用方法
方法声明 | 功能描述 |
---|---|
static <T> boolean addAll(Collection<? super T> c, T... elements) | 向集合 c 中添加多个元素(可变参数) |
static int frequency(Collection<?> c, Object o) | 统计元素 o 在集合 c 中出现的次数 |
static boolean disjoint(Collection<?> c1, Collection<?> c2) | 判断两个集合是否无交集(无共同元素) |
代码示例:其他方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsOtherDemo {
public static void main(String[] args) {
// 1. 批量添加元素
List<String> list = new ArrayList<>();
Collections.addAll(list, "Java", "Python", "C++", "Java");
System.out.println("批量添加后:" + list); // [Java, Python, C++, Java]
// 2. 统计元素出现次数
int count = Collections.frequency(list, "Java");
System.out.println("Java出现次数:" + count); // 2
// 3. 判断集合是否无交集
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
List<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(4);
List<Integer> list3 = new ArrayList<>();
list3.add(2);
list3.add(5);
boolean isDisjoint1 = Collections.disjoint(list1, list2);
boolean isDisjoint2 = Collections.disjoint(list1, list3);
System.out.println("list1与list2无交集:" + isDisjoint1); // true(无共同元素)
System.out.println("list1与list3无交集:" + isDisjoint2); // false(有共同元素2)
}
}
三、Collections
与 Arrays
的区别
Collections
:操作集合对象(List
、Set
、Map
等)。Arrays
:操作数组(如数组排序Arrays.sort()
、数组转集合Arrays.asList()
等)。
两者均为工具类,方法均为静态,分别处理集合和数组的常见操作。
四、最佳实践
- 避免返回
null
:方法返回集合时,若无数据,返回Collections.emptyList()
等空集合,而非null
,减少NullPointerException
。 - 线程安全选择:简单线程安全场景可用
synchronizedList()
等,但高并发推荐java.util.concurrent
包下的集合。 - 不可修改保护:当需要传递集合但不允许修改时,使用
unmodifiableList()
等包装,保护数据完整性。 - 排序前检查:使用
binarySearch()
前必须确保集合已排序,否则结果不可靠。
总结
Collections
工具类是 Java 集合操作的“瑞士军刀”,提供了排序、查找、同步化、不可修改化等实用功能,极大简化了集合处理代码。掌握其核心方法,能显著提高开发效率,同时保证代码的安全性和可读性。实际开发中,需根据场景灵活选择合适的方法,尤其注意线程安全和不可修改集合的特性。