起因:工作中需要对集合进行一个乱序的重排序,当时不太记得Collections中的方法,去百度了一下,发现Collections工具类提供了相应的方法,之前有用过Collections其中的一些方法,但是没有对其API有一个系统的学习和记录,这次记录一下。知道这里有了,用的时候也好找了。
Collections是 JDK提供的工具类,提供了一系列静态方法,方便操作各种集合。分析和总结一下其API,记录一下。
Collections主要有以下几个功能
- 排序
- 乱序(洗牌)
- 替换
- 创建空集合
- 创建单元集合
- 不可变集合
- 线程安全集合
接下来稍微介绍一下相关操作与demo,其实看api更好。
1.排序
- reverse(List list):反转指定List集合中元素的顺序
- shuffle(List list):对List中的元素进行随机排序(洗牌)
- sort(List list):对List里的元素根据自然升序排序
- sort(List list, Comparator c):自定义比较器进行排序
- swap(List list, int i, int j):将指定List集合中i处元素和j出元素进行交换
- rotate(List list, int distance):将所有元素向右移位指定长度,如果distance等于size那么结果不变
Collections可以对List进行sort排序。因为排序会直接修改List元素的位置,因此必须传入可变List。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("pear");
list.add("orange");
// 排序前:
System.out.println(list);
Collections.sort(list);
// 排序后:
System.out.println(list);
}
排序也是有讲究的。列表中的所有元素必须实现Comparable接口
,因为最终还是要根据Comparable中的方法来对其实施排序。以下是JDK源码。
除了默认排序还有自定义排序,自定义排序需要传入Comparator比较器。一般使用compare(T o1, T o2)方法就可以了,比较常用的还有reversed()方法,到排序。详情见我的另一篇,排序!
//默认排序
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
//自定义排序
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
2.乱序(洗牌)
Collections提供了洗牌算法,即传入一个有序的List,可以随机打乱List内部元素的顺序,效果相当于让计算机洗牌:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i=0; i<10; i++) {
list.add(i);
}
// 洗牌前:
System.out.println(list);
Collections.shuffle(list);
// 洗牌后:
System.out.println(list);
}
排序其实就是拿到传入的list,然后对任意两个元素交换位置,也可以传入一个带随机数的,没看源码,有空可以了解一下。
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
private static Random r;
//--------------------------------------
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray();
// Shuffle array
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// Dump array back into list
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
//--------------------------------------
private static void swap(Object[] arr, int i, int j) {
Object tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
3. 查找和替换
- binarySearch(List list, Object key):使用二分搜索法,以获得指定对象在List中的索引,前提是集合已经排序
- max(Collection coll):返回最大元素
- max(Collection coll, Comparator comp):根据自定义比较器,返回最大元素
- min(Collection coll):返回最小元素
- min(Collection coll, Comparator comp):根据自定义比较器,返回最小元素
- fill(List list, Object obj):使用指定对象填充
- frequency(Collection Object o):返回指定集合中指定对象出现的次数
- replaceAll(List list, Object old, Object new):替换
4.创建空集合
Collections提供了一系列方法来创建空集合:
创建空List:List<T> emptyList()
创建空Map:Map<K, V> emptyMap()
创建空Set:Set<T> emptySet()
要注意到返回的空集合是不可变集合,无法向其中添加或删除元素。
此外,也可以用各个集合接口提供的of(T...)方法创建空集合。例如,以下创建空List的两个方法是等价的:
List<String> list1 = List.of();
List<String> list2 = Collections.emptyList();
创建新的集合现在都在用Guava 的Lists.asList(),之后再记录一下
public static <E> List<E> asList(@Nullable E first, E[] rest) {
return new OnePlusArrayList<E>(first, rest);
}
5.创建单元素集合
Collections提供了一系列方法来创建一个单元素集合:
创建一个元素的List:List<T> singletonList(T o)
创建一个元素的Map:Map<K, V> singletonMap(K key, V value)
创建一个元素的Set:Set<T> singleton(T o)
要注意到返回的单元素集合也是不可变集合,无法向其中添加或删除元素。
此外,也可以用各个集合接口提供的of(T...)方法创建单元素集合。例如,以下创建单元素List的两个方法是等价的:
List<String> list1 = List.of("apple");
List<String> list2 = Collections.singletonList("apple");
实际上,使用List.of(T...)更方便,因为它既可以创建空集合,也可以创建单元素集合,还可以创建任意个元素的集合:
List<String> list1 = List.of(); // empty list
List<String> list2 = List.of("apple"); // 1 element
List<String> list3 = List.of("apple", "pear"); // 2 elements
List<String> list4 = List.of("apple", "pear", "orange"); // 3 elements
6.不可变集合
Collections还提供了一组方法把可变集合封装成不可变集合:
封装成不可变List:List<T> unmodifiableList(List<? extends T> list)
封装成不可变Set:Set<T> unmodifiableSet(Set<? extends T> set)
封装成不可变Map:Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m)
这种封装实际上是通过创建一个代理对象,拦截掉所有修改方法实现的。类似与Guava 的ImmutableMap
我的另一篇Guava 的ImmutableMap
7.线程安全集合
自从有了juc,基本没啥用,就不写了。
不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!