241. Java 集合 - 使用 Collections 工厂类处理集合
Collections 工厂类提供了一组方法来操作集合及其内容,包含了约 70 个方法。在本节中,我们将重点介绍其中的一部分。
🏆 提取集合中的最小值或最大值
Collections 类提供了两个方法 min() 和 max() 来提取集合中的最小值和最大值。你可以通过以下两种方式调用它们:
- 不带比较器 :如果没有提供比较器,集合中的元素必须实现
Comparable接口,否则会抛出ClassCastException异常。 - 带比较器 :如果提供了一个比较器,
min()和max()将使用它来确定最小值或最大值,无论集合元素是否实现Comparable。
示例:获取最小值和最大值
java
List<Integer> numbers = List.of(5, 2, 9, 1, 7);
int min = Collections.min(numbers);
int max = Collections.max(numbers);
System.out.println("Min: " + min + ", Max: " + max);
注意:
- 对于空集合,调用
min()或max()方法会抛出NoSuchMethodException异常。
🔍 查找列表中的子列表
Collections 类提供了两个方法来查找子列表在更大列表中的位置:
indexOfSublist(List<?> source, List<?> target):返回目标列表中第一个元素在源列表中的索引。如果目标列表不存在,返回-1。lastIndexOfSublist(List<?> source, List<?> target):返回目标列表最后一个元素在源列表中的索引。
示例:查找子列表
java
List<String> source = List.of("a", "b", "c", "d", "e");
List<String> target = List.of("c", "d");
int index = Collections.indexOfSubList(source, target);
System.out.println("Index of sublist: " + index);
输出:
java
Index of sublist: 2
🔄 更改列表元素的顺序
Collections 类提供了几个方法来改变列表中元素的顺序:
sort():按升序排序列表。可以传入一个Comparator,如果没有,则要求元素必须实现Comparable接口。自 Java SE 8 以来,推荐使用List接口中的sort()方法。shuffle():随机打乱列表元素的顺序。可以传入一个Random实例,如果需要可重复的随机顺序。rotate():旋转列表的元素。旋转后,索引 0 的元素将移动到索引 1,依此类推,最后的元素将移动到列表的开头。
示例:旋转列表元素
java
List<String> strings = Arrays.asList("0", "1", "2", "3", "4");
System.out.println("Before rotate: " + strings);
Collections.rotate(strings, 1); // 向右旋转
System.out.println("After rotate: " + strings);
输出:
java
Before rotate: [0, 1, 2, 3, 4]
After rotate: [4, 0, 1, 2, 3]
reverse():反转列表中元素的顺序。swap():交换列表中的两个元素。
示例:反转列表
java
List<String> strings = Arrays.asList("a", "b", "c", "d");
Collections.reverse(strings);
System.out.println("Reversed list: " + strings);
输出:
java
Reversed list: [d, c, b, a]
🛡️ 包装集合为不可变集合
Collections 工厂类提供了几种方法,用于创建集合的不可变包装器。包装后的集合无法修改,任何修改操作都会抛出异常。重要的是,这些方法返回的是包装器,而不是集合的副本,所以如果原集合被修改,包装器也会反映出这些变化。
这些方法的命名遵循一定规则,通常以 unmodifiable 开头。例如,要创建一个不可变的 List 包装器,你可以使用 unmodifiableList() 方法。
示例:创建不可变列表
java
List<String> strings = new ArrayList<>(Arrays.asList("0", "1", "2", "3", "4"));
List<String> immutableStrings = Collections.unmodifiableList(strings);
System.out.println(immutableStrings);
// 下面的代码会抛出 UnsupportedOperationException 异常
immutableStrings.add("5");
输出:
java
[0, 1, 2, 3, 4]
注意 :如果你修改了原始集合(strings),它也会反映在不可变集合中。这是因为不可变包装器仅仅是原集合的一个视图。
🔒 包装集合为同步集合
和创建不可变集合类似,Collections 工厂类还可以创建同步集合的包装器。同步集合确保在多线程环境下安全访问。
同步集合的命名规则为:synchronized 后跟集合类型名称。例如,要创建同步的 List,你可以使用 synchronizedList() 方法。
示例:创建同步列表
java
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>(Arrays.asList("a", "b", "c")));
注意事项:
- 所有对集合的访问必须通过同步包装器进行。
- 在遍历集合时,使用迭代器或流时,代码需要进行同步操作,以避免竞态条件。
尽管 Collections 提供了同步集合,但 Java.util.concurrent 包中的类通常提供了更好的并发解决方案。
📜 小结
min()和max():提取集合中的最小值和最大值,支持使用比较器。indexOfSubList()和lastIndexOfSubList():查找子列表在大列表中的位置。- 排序和顺序操作 :
sort(),shuffle(),rotate(),reverse()和swap()提供了多种操作集合顺序的方法。 - 不可变集合包装 :使用
unmodifiable系列方法创建不可变集合,修改原集合会反映到不可变集合中。 - 同步集合包装 :使用
synchronized系列方法创建同步集合,确保线程安全。
问题 :如何通过 Collections 类创建一个不可变的 List? 答案 :你可以使用 Collections.unmodifiableList() 方法创建一个不可变的 List,但要小心,如果原始集合被修改,包装器也会反映这些变化。