Java 集合工具类
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>() {@Overridepublic 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); // 1System.out.println("子列表最后出现索引:" + last); // 3// 3. 替换元素boolean replaced = Collections.replaceAll(list, "B", "X");System.out.println("是否替换成功:" + replaced); // trueSystem.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); // 8System.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) {// 非线程安全的ListList<String> unsafeList = new ArrayList<>();// 转换为线程安全的ListList<String> safeList = Collections.synchronizedList(unsafeList);// 非线程安全的MapMap<String, Integer> unsafeMap = new HashMap<>();// 转换为线程安全的MapMap<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()); // 0System.out.println("空Set是否为空:" + emptySet.isEmpty()); // true// 尝试修改空集合(抛异常)try {emptyList.add("test");} catch (UnsupportedOperationException e) {System.out.println("空集合修改错误:" + e.getMessage());}// 实际应用:方法返回空集合而非nullList<String> result = getData();System.out.println("方法返回的集合大小:" + result.size()); // 0(避免NPE)}// 模拟查询数据,无结果时返回空集合而非nullpublic 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 集合操作的“瑞士军刀”,提供了排序、查找、同步化、不可修改化等实用功能,极大简化了集合处理代码。掌握其核心方法,能显著提高开发效率,同时保证代码的安全性和可读性。实际开发中,需根据场景灵活选择合适的方法,尤其注意线程安全和不可修改集合的特性。
如需巩固本文内容,可点击以下链接完成相关练习:点击此处进入练习题。