一、概述
Collections类是针对集合操作的工具类,提供了许多静态方法来对Set、List、Map进行操作(排序、查找、填充元素)。通过使用这些方法,可以简化集合操作代码,提高代码的可读性和可靠性。
二、常用方法
1、排序操作:主要有sort()、reverse()、shuffle()、swap()等方法,用于改变集合中元素的顺序。
- 1)、sort():对集合中的元素进行排序。主要有两种重载形式:
- Ⅰ、void sort(List<T> list):对指定列表中的元素进行升序排序,但列表中的元素所对应的类必须实现Comparable接口,否则编译不通过。
public class CollectionsTest { public static void main(String[] args) { // 1、void sort(List<T> list):对集合中的元素进行排序。 // 1)、Java内置类的集合进行排序 List<Integer> list = Arrays.asList(3, 55, 11, 4, 99); System.out.println("排序前:" + list); // [3, 55, 11, 4, 99] Collections.sort(list); System.out.println("排序后:" + list); // [3, 4, 11, 55, 99] // 2)、自定义类的集合进行排序:自定义类必须实现Comparable接口 List<Student> studentList = new ArrayList<>(Arrays.asList( new Student("张三", 24), new Student("李四", 14), new Student("王五", 34) )); System.out.println("排序前:" + studentList); // [Person{name='张三', age=24}, Person{name='李四', age=14}, Person{name='王五', age=34}] Collections.sort(studentList); System.out.println("排序后:" + studentList); // [Person{name='李四', age=14}, Person{name='张三', age=24}, Person{name='王五', age=34}] } } // 集合元素对应的类需要实现Comparable自然排序接口 public class Student implements Comparable<Student>{ private String name; private Integer age; public Student(String name, Integer age) { this.name = name; this.age = age; } @Override public int compareTo(Student o) { return this.age.compareTo(o.getAge()); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
- Ⅱ、void sort(List<T> list, Comparator<? super T> c):使用指定的Comparator比较器对指定列表中的元素进行排序。
public class CollectionsTest { public static void main(String[] args) { // 2、 void sort(List<T> list, Comparator<? super T> c):使用指定的Comparator比较器对指定列表进行排序 // 1)、Java内置类的集合进行排序 List<Integer> list = Arrays.asList(3, 55, 11, 4, 99); System.out.println("排序前:" + list); // [3, 55, 11, 4, 99] Collections.sort(list, (o1, o2) -> o1 -o2); System.out.println("升序排序后:" + list); // [3, 4, 11, 55, 99] Collections.sort(list, (o1, o2) -> o2 -o1); System.out.println("降序排序后:" + list); // [99, 55, 11, 4, 3] // 2)、自定义类的集合进行排序:自定义类不需要实现Comparable接口 List<Person> people = new ArrayList<>(Arrays.asList( new Person("张三", 24), new Person("李四", 14), new Person("王五", 34) )); System.out.println("排序前:" + people); // [Person{name='张三', age=24}, Person{name='李四', age=14}, Person{name='王五', age=34}] Collections.sort(people, Comparator.comparingInt(Person::getAge)); System.out.println("升序排序后:" + people); // [Person{name='李四', age=14}, Person{name='张三', age=24}, Person{name='王五', age=34}] Collections.sort(people, Comparator.comparingInt(Person::getAge).reversed()); System.out.println("降序排序后:" + people); // [Person{name='李四', age=14}, Person{name='张三', age=24}, Person{name='王五', age=34}] } }
- Ⅰ、void sort(List<T> list):对指定列表中的元素进行升序排序,但列表中的元素所对应的类必须实现Comparable接口,否则编译不通过。
- 2)、void reverse(List<?> list):反转集合中的元素。
// void reverse(List<?> list):反转集合中的元素 List<Integer> list = Arrays.asList(3, 55, 11, 4, 99); System.out.println("反转前:" + list); // [3, 55, 11, 4, 99] Collections.reverse(list); System.out.println("反转后:" + list); // [99, 4, 11, 55, 3]
- 3)、shuffle():对集合中的元素随机排列(打乱顺序)。主要有两种重载形式:
- Ⅰ、void shuffle(List<?> list):使用默认的随机性(通过内部创建一个 Random 对象来实现)对指定集合的元素进行随机重新排序。
// 1)、shuffle(List<?> list):使用默认的随机性对指定集合的元素进行随机重新排序。 List<Integer> list = Arrays.asList(3, 55, 11, 4, 99); System.out.println("随机前:" + list); // [3, 55, 11, 4, 99] Collections.shuffle(list); System.out.println("默认随机后:" + list); // [99, 4, 55, 3, 11]
- Ⅱ、void shuffle(List<?> list, Random rnd):使用指定的随机性(即传入的 Random 对象)对指定集合的元素进行随机重新排序。这允许开发者控制随机性的来源,以便在需要时重现相同的随机序列。
// 2)、void shuffle(List<?> list, Random rnd):使用指定的随机性对集合的元素进行随机重新排序。 List<Integer> list2 = Arrays.asList(3, 55, 11, 4, 99); Collections.shuffle(list2, new Random(10)); System.out.println("指定随机后:" + list2); // [99, 11, 3, 55, 4] List<Integer> list3 = Arrays.asList(3, 55, 11, 4, 99); Collections.shuffle(list3, new Random(10)); // 重现与list2相同的随机序列 System.out.println("指定随机后:" + list3);// [99, 11, 3, 55, 4]
- Ⅰ、void shuffle(List<?> list):使用默认的随机性(通过内部创建一个 Random 对象来实现)对指定集合的元素进行随机重新排序。
- 4)、void swap(List<?> list, int i, int j):将集合中索引为 i 和 j 位置的元素交换位置。
// void swap(List<?> list, int i, int j):将i和j位置的元素交换位置。 List<Integer> list = Arrays.asList(3, 55, 11, 4, 99); System.out.println("交换之前:" + list); // [3, 55, 11, 4, 99] Collections.swap(list, 1, 4); System.out.println("交换之后:" + list); // [3, 99, 11, 4, 55]
2、查找操作:主要有binarySearch()、max()、min()、frequency()等方法。
- 1)、binarySearch():使用二分查找法在已排序的集合中查找指定元素的位置。主要有两种重载形式:
- Ⅰ、int binarySearch(List<? extends Comparable<? super T>> list, T key):基于自然排序的方式查找,即集合中的元素必须实现Comparable接口,返回查找的元素的索引,如果不存在则返回-1。
// 1、binarySearch(list, key):基于自然排序的方式查找,返回查找的元素的索引,如果不存在则返回-1 // 1)、Java内置类的集合进行查找 List<Integer> list = Arrays.asList(3, 555, 777, 4, 99); System.out.println("排序前查找:"); System.out.println(Collections.binarySearch(list, 3)); // 输出0 System.out.println(Collections.binarySearch(list, 4)); // 输出-2,因为没有先对list进行排序 Collections.sort(list); System.out.println("排序后查找:"); System.out.println(Collections.binarySearch(list, 3)); // 输出0 System.out.println(Collections.binarySearch(list, 4)); // 输出1 System.out.println(Collections.binarySearch(list, 1)); // 输出-1,元素不存在 // 2)、对象集合进行查找:集合中元素对应的类必须实现Comparable自然排序接口 List<Student> students = new ArrayList<>(Arrays.asList( new Student("张三", 24), // PS:Student类实现了Comparable接口实现按年龄升序排序 new Student("李四", 14), new Student("王五", 34) )); int index1 = Collections.binarySearch(students, new Student("张三", 24)); System.out.println("排序前查找:" + index1); // -3,因为没有先对students进行排序 Collections.sort(students); // 根据年龄字段进行排序 int index2 = Collections.binarySearch(students, new Student("张三", 24)); System.out.println("排序后查找:" + index2); // 输出1
- Ⅱ、int binarySearch(List<? extends T> list, T key, Comparator<? super T> c):基于自定义排序的方式查找,需要在第三个参数中传入一个自定义比较器Comparator,返回查找的元素的索引,如果不存在则返回-1。
// 2、binarySearch(list, key, c)基于自定义排序的方式查找 // 需要在第三个参数中传入一个自定义比较器Comparator,返回查找的元素的索引,如果不存在则返回-1。 List<Integer> list = Arrays.asList(3, 555, 777, 4, 99); Collections.sort(list); // 同样需要先对list进行排序 System.out.println("查找元素:"); Comparator<Integer> comparator = (o1, o2) -> o1 - o2; System.out.println(Collections.binarySearch(list, 3, comparator)); // 输出0 System.out.println(Collections.binarySearch(list, 4, comparator)); // 输出1 System.out.println(Collections.binarySearch(list, 1, comparator)); // 输出-1,因为元素不存在 // 2)、对象集合进行查找:第三个参数传入了比较器,所以Person类不需要实现Comparator接口 List<Person> people = new ArrayList<>(Arrays.asList( new Person("张三", 24), new Person("李四", 14), new Person("王五", 34) )); Collections.sort(people, Comparator.comparingInt(Person::getAge)); // 根据年龄进行进行升序排序 System.out.println("根据年龄进行查找:"); int index1 = Collections.binarySearch(people, new Person("张三", 24), Comparator.comparing(Person::getAge)); System.out.println(index1); // 输出1 int index2 = Collections.binarySearch(people, new Person("李四", 14), Comparator.comparing(Person::getAge)); System.out.println(index2); // 输出0 int index3 = Collections.binarySearch(people, new Person("李四", 33), Comparator.comparing(Person::getAge)); System.out.println(index3); // 输出-3,负数就表示元素不存在(根据年龄33)
- Ⅰ、int binarySearch(List<? extends Comparable<? super T>> list, T key):基于自然排序的方式查找,即集合中的元素必须实现Comparable接口,返回查找的元素的索引,如果不存在则返回-1。
- 2)、max()/min():查找集合中最大/最小的元素,主要有两种重载形式:
- Ⅰ、<T extends Object & Comparable<? super T>> T max/min(Collection<? extends T> coll):基于自然排序的方式查找,即集合中的元素必须实现Comparable接口,使用元素的自然顺序来找出最大/最小元素。
// 1)、max/min(Collection<? extends T> coll):基于自然排序的方式查找 List<Integer> list = Arrays.asList(3, 555, 777, 4, 99); Integer max = Collections.max(list); Integer min = Collections.min(list); System.out.println("集合中元素的最大值为:" + max); // 输出777 System.out.println("集合中元素的最小值为:" + min); // 输出3
- Ⅱ、<T> T max(Collection<? extends T> coll, Comparator<? super T> comp):基于自定义排序的方式查找,需要在第二个参数中传入一个自定义比较器Comparator,使用指定的比较器来找出最大/最小元素。
// 2)、max(Collection<? extends T> coll, Comparator<? super T> comp):基于自定义排序的方式查找, List<Person> people = new ArrayList<>(Arrays.asList( new Person("张三", 24), new Person("李四", 14), new Person("王五", 34) )); Person maxPerson = Collections.max(people, Comparator.comparingInt(Person::getAge)); Person minPerson = Collections.min(people, Comparator.comparingInt(Person::getAge)); System.out.println("年龄最大的为:" + maxPerson); // 输出Person{name='王五', age=34} System.out.println("年龄最小的为:" + minPerson); // 输出Person{name='李四', age=14}
- Ⅰ、<T extends Object & Comparable<? super T>> T max/min(Collection<? extends T> coll):基于自然排序的方式查找,即集合中的元素必须实现Comparable接口,使用元素的自然顺序来找出最大/最小元素。
- 3)、int frequency(Collection<?> c, Object o):返回指定元素在集合中出现的次数。如果是对象集合则根据对象的equals()进行匹配。
// 4、frequency(Collection<?> c, Object o):返回指定元素在集合中出现的次数。 List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 2, 3, 4, 2)); int frequency = Collections.frequency(list, 2); System.out.println("元素2出现的次数: " + frequency); // 输出3 System.out.println("元素5出现的次数: " + Collections.frequency(list, 5)); // 输出0 Person p1 = new Person("张三", 24); Person p2 = new Person("李四", 14); Person p3 = new Person("王五", 34); List<Person> people = Arrays.asList(p1, p2, p3); System.out.println(Collections.frequency(people, new Person("张三", 24))); // 输出0 System.out.println(Collections.frequency(people, p1)); // 输出1,根据的是equals()来进行匹配
3、填充操作fill():用指定元素替换列表中的所有元素。
// 1、void fill(List<? super T> list, T obj)→ 用指定元素替换列表中的所有元素。
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Collections.fill(list, 0);
System.out.println("将集合中所有的元素都替换为0:" + list); // [0, 0, 0, 0, 0]
4、替换操作:boolean replaceAll(List<T> list, T oldVal, T newVal) → 将集合中指定元素全部替换成新的值。
// 1、boolean replaceAll(List<T> list, T oldVal, T newVal): 将集合中指定元素全部替换成新的值。
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 2, 3, 4, 2));
System.out.println("替换前:" + list); // [1, 2, 2, 3, 4, 2]
Collections.replaceAll(list, 2, 9);
System.out.println("替换后:" + list); // [1, 9, 9, 3, 4, 9]
Person p1 = new Person("张三", 24);
Person p2 = new Person("李四", 14);
Person p3 = new Person("王五", 34);
List<Person> people = new ArrayList<>(Arrays.asList(p1, p2, p3));
System.out.println(people); // [Person{name='张三', age=24}, Person{name='李四', age=14}, Person{name='王五', age=34}]
Collections.replaceAll(people, p1, new Person("张三", 25));
System.out.println(people); // [Person{name='张三', age=25}, Person{name='李四', age=14}, Person{name='王五', age=34}]
5、判断操作:boolean disjoint(Collection<?> c1, Collection<?> c2) → 判断两个集合是否没有任何共同元素,返回一个boolean值。
// 1、boolean disjoint(集合1, 集合2):判断两个集合是否没有任何共同元素,是则返回true,否则返回false。
List<Integer> list1 = new ArrayList<>(Arrays.asList(1, 2, 3));
List<Integer> list2 = new ArrayList<>(Arrays.asList(4, 5, 6));
List<Integer> list3 = new ArrayList<>(Arrays.asList(1, 3, 5));
System.out.println("list1和list2是否没有任何共同元素:" + Collections.disjoint(list1, list2)); // true
System.out.println("list1和list3是否没有任何共同元素:" + Collections.disjoint(list1, list3)); // false
System.out.println("list2和list2是否没有任何共同元素:" + Collections.disjoint(list2, list3)); // false
6、不可变集合:Collections类提供了多种创建不可变的集合的方法,对不可变集合执行增删改操作时就会报错。不可变集合是线程安全、能够保证数据不变性以及在某些情况下提高性能(因为不可变对象可以被安全地缓存和共享)。
- 1)、使用场景:
- Ⅰ、多线程环境:在多线程环境中,不可变集合是线程安全的。多个线程可以同时访问和读取不可变集合,无需额外的同步机制。这样可以提高并发性能,并减少线程竞争和数据不一致性的问题。
- Ⅱ、缓存:用来存储缓存的数据,可以避免在缓存中发生数据修改和同步的问题,从而提高缓存的性能和可靠性。
- Ⅲ、方法返回值:作为方法的返回值,确保方法调用者无法修改返回的集合。提搞了安全性和稳定性,避免在方法调用过程中数据被意外修改。
- Ⅳ、数据保护:用于存储需要保护数据完整性的数据,即使集合被其他代码引用也无法修改其中的元素。例如配置信息、常量数据等。
- Ⅴ、函数式编程:使用不可变集合可以更容易地实现纯函数(即没有副作用的函数),从而提高代码的可读性和可维护性。
- Ⅵ、防御式编程:在编程中,有时候可能无法完全控制外部对内部数据的访问和修改。使用不可变集合可以防止外部代码意外地修改内部数据,从而提高代码的健壮性和稳定性。
- 2)、注意事项:
- Ⅰ、任何尝试修改不可变集合的操作都会抛出 UnsupportedOperationException 异常。
- Ⅱ、原始集合修改了会影响到不可变集合。
- 3)、常用的不可变集合:主要有emptyXxx()、singletoXxx()、unmodifiableXxx()三个系列。
- Ⅰ、emptyXxx():创建一个空的不可变集合。主要的方法有以下:
- ①、final <T> List<T> emptyList():创建一个空的、不可变的List集合。
- ②、final <T> Set<T> emptySet():创建一个空的、不可变的的Set集合。
- ③、<E> SortedSet<E> emptySortedSet():创建一个空的、不可变的SortedSet集合。
- ④、final <K,V> Map<K,V> emptyMap():创建一个空的、不可变的Map集合。
- ⑤、final <K,V> SortedMap<K,V> emptySortedMap() :创建一个空的、不可变的SortedMap集合。
// 1、emptyXxx()系列:空的不可变集合 List<String> emptyList = Collections.emptyList(); System.out.println(emptyList); // 输出 [] Set<String> emptySet = Collections.emptySet(); System.out.println(emptySet); // 输出 [] SortedSet<String> emptySortedSet = Collections.emptySortedSet(); System.out.println(emptySortedSet); // 输出 [] Map<String, Integer> emptyMap = Collections.emptyMap(); System.out.println(emptyMap); // 输出 {} SortedMap<String, Integer> emptySortedMap = Collections.emptySortedMap(); System.out.println(emptySortedMap); // 输出 {}
- Ⅱ、singletoXxx():创建一个只有一个元素的不可变集合。主要的方法有以下:
- ①、<T> List<T> singletonList(T o):创建一个只包含一个元素、不可变的List集合。
- ②、<T> Set<T> singleton(T o):创建一个只包含一个元素、不可变的Set集合。
- ③、<K,V> Map<K,V> singletonMap(K key, V value):创建一个只包含一个键值对、不可变的Map集合。
// 2、singletoXxx()系列:只有一个元素的不可变集合 List<String> singletonList = Collections.singletonList("张三"); System.out.println(singletonList); // 输出 [张三] Set<String> singletonSet = Collections.singleton("李四"); System.out.println(singletonSet); // 输出 [李四] Map<String, Integer> singletonMap = Collections.singletonMap("张三", 23); System.out.println(singletonMap); // 输出 {张三=23}
- Ⅲ、unmodifiableXxx():为指定集合创建一个不可变集合。主要的方法有以下:
- ①、<T> List<T> singletonList(T o):创建一个只包含一个元素、不可变的List集合。
- ②、<T> Set<T> singleton(T o):创建一个只包含一个元素、不可变的Set集合。
- ③、<K,V> Map<K,V> singletonMap(K key, V value):创建一个只包含一个键值对、不可变的Map集合。
// 3、unmodifiableXxx()系列:为指定集合创建一个不可变集合 List<String> list = new ArrayList<>(Arrays.asList("zhangsan", "lisi", "wangwu")); List<String> unmodifiableList = Collections.unmodifiableList(list); System.out.println(unmodifiableList); // 输出 [zhangsan, lisi, wangwu] HashSet<String> set = new HashSet<>(list); Set<String> unmodifiableSet = Collections.unmodifiableSet(set); System.out.println(unmodifiableSet); // 输出 [lisi, zhangsan, wangwu] TreeSet<String> treeSet = new TreeSet<>(set); SortedSet<String> unmodifiableSortedSet = Collections.unmodifiableSortedSet(treeSet); System.out.println(unmodifiableSortedSet); // 输出 [lisi, wangwu, zhangsan] Map<String, Integer> map = new HashMap<>(); map.put("张三", 25); Map<String, Integer> unmodifiableMap = Collections.unmodifiableMap(map); System.out.println(unmodifiableMap); // 输出 {张三=25} TreeMap<String, Integer> treeMap = new TreeMap<>(); treeMap.put("李四", 35); SortedMap<String, Integer> unmodifiableSortedMap = Collections.unmodifiableSortedMap(treeMap); System.out.println(unmodifiableSortedMap); // 输出 {李四=35}
- Ⅰ、emptyXxx():创建一个空的不可变集合。主要的方法有以下:
7、同步控制集合:Collections类提供了多种同步控制集合的方法,同步控制集合是线程安全的,在多线程环境下可以安全地访问和修改集合。主要为synchronizedXXX()系列的方法:
- 1)、<T> Collection<T> synchronizedCollection(Collection<T> c):根据指定集合创建一个同步的Collection集合。
- 2)、<T> List<T> synchronizedList(List<T> list):根据指定List创建一个同步的List集合。
- 3)、<T> Set<T> synchronizedSet(Set<T> s):根据指定Set创建一个同步的Set集合。
- 4)、<T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s):根据指定SortedSet创建一个同步的SortedSet集合。
- 5)、<K,V> Map<K,V> synchronizedMap(Map<K,V> m):根据指定Map创建一个同步的Map集合。
- 6)、<K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m):根据指定SortedMap创建一个同步的SortedMap集合。
// 同步控制集合
// 1、创建同步控制集合
Collection<Object> synchronizedCollection = Collections.synchronizedCollection(new ArrayList<>());
System.out.println(synchronizedCollection); // 输出 []
List<Object> synchronizedList = Collections.synchronizedList(new ArrayList<>());
System.out.println(synchronizedList); // 输出 []
Set<Object> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
System.out.println(synchronizedSet); // 输出 []
SortedSet<Object> synchronizedSortedSet = Collections.synchronizedSortedSet(new TreeSet<>());
System.out.println(synchronizedSortedSet); // 输出 []
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
System.out.println(synchronizedMap); // 输出 {}
SortedMap<String, Integer> synchronizedSortedMap = Collections.synchronizedSortedMap(new TreeMap<>());
System.out.println(synchronizedSortedMap); // 输出 {}
// 2、迭代同步控制集合
List<Integer> list = new ArrayList<>(Arrays.asList(1, 44, 33, 22, 677));
List<Integer> synchronizedList1 = Collections.synchronizedList(list);
synchronized (synchronizedList1) {
for (Integer integer : synchronizedList1) {
System.out.println(integer); // 输出每一个元素
}
}