背景
Collections集合接口类在java开发中经常使用到,非常有必要走读一下。
下面我们将把这个类中的函数进行粗略的分类介绍,算是提纲挈领吧。
走读+实战
获取不可变空集合
Collections.empty*****
以下为阿里规约中的一些阐述
一般在函数返回数组的时候,会使用到这些空的集合,主要是防止上层使用的时候空指针的出现(毕竟每次都得判断是不是null,很不优雅)
单元素集合
Collections.singleton**
这个似乎有点鸡肋,集合中只能有一个元素,而且不能更改,只能用于某些特殊场景了(博主暂时没有必然用到的时候)
排序与查找
Collections.sort*
Collections.Search*
排序有两个函数,第一个是默认排序,第二个可以传入Comparator。
查找接口,只提供了二分查找的方法(即binarySearch),所以在查找之前需要进行排序。
/**
* 二分法查找,前提需要排序,查找效率极高,是indexOf的十倍以上,下面测试一下
*/
private static void binarySearch() {
System.out.println("----------------------");
List<String> list1 = new ArrayList<>();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
list1.add(i + "");
}
// 注意二分查找必须要进行排序才可以
Collections.sort(list1);
System.out.println("制造序列需要的时间:" + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(list1.indexOf("777777"));
System.out.println(String.format("indexOf,使用时间:%d", System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Collections.binarySearch(list1, "777777"));
System.out.println(String.format("binarySearch 二分法,使用时间:%d", System.currentTimeMillis() - start));
}
元素位置变换
打散shuffle、列表翻转reverse、元素对换swap等操作,另外还有旋转rotate。
rotate的例子如下:
List<String> list = Lists.newArrayList("1", "2", "3", "4", "5");
Collections.rotate(list, 1);
System.out.println(list);
获取极值
Collections.min或者Collections.max,获取极大极小值。
List<String> list = Lists.newArrayList("123", "2321");
Collections.sort(list);
System.out.println(list);
System.out.println(Collections.max(list));
public class CollectionDemo {
public static void main(String[] args) throws Exception {
newEmptyCollection();
addAll();
asLifoQueue();
binarySearch();
checkedCollections();
}
private static void asLifoQueue() {
System.out.println("----------------------");
// 必须是LinkedList
LinkedList<String> list1 = new LinkedList<>();
Queue<String> queue = Collections.asLifoQueue(list1);
// 入栈
System.out.println(queue.offer("11"));
System.out.println(String.format("offer入栈后,queue的长度是:%d", queue.size()));
// 出栈
System.out.println(queue.poll());
System.out.println(String.format("poll出栈后,queue的长度是:%d", queue.size()));
queue.offer("11");
queue.offer("22");
queue.offer("33");
System.out.println(String.format("第一个元素 %s", queue.element()));
// peek方法和element方法差不多,不推荐使用
}
private static void checkedCollections() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.println("----------------------");
List<String> list = new ArrayList<>(16);
list = Collections.checkedList(list, String.class);
list.add("string1");
// 生成检查容器之后,不能在容器中添加其他类型,下面的反射也获取不到对应的方法
Method method = list.getClass().getDeclaredMethod("add", Object.class);
method.invoke(list, 1);
}
拷贝、填充、覆盖
先说拷贝 copy,参数(dst, src),实现把src的拷贝到dst里面,注意,dst的长度不能比第二个少。
拷贝的结果是如下,大家一看便知
List<String> list = Arrays.asList("1", "1");
List<String> list1 = Arrays.asList("2", "2", "2");
Collections.copy(list1, list);
System.out.println(list);
System.out.println(list1);
填充函数非常容易理解,直接上代码吧
List<String> list = Arrays.asList("1", "1");
Collections.fill(list, "3");
System.out.println(list);
再来看看覆盖,其中核心思想是遍历+equals,进行元素替换,先来看下源码。
since 1.4,不算是新接口,能明显的看到,是直接遍历的列表,并且能每次都进行元素的equals操作,然后直接进行替换。
这里注意下,既然是用的equals,那么对于hashCode要格外的注意了。
实战代码如下:
List<String> list = Arrays.asList("1", "1", "2");
Collections.replaceAll(list, "1", "3");
System.out.println(list);
先入后出队列asLifoQueue
lifo(英文:last in fisrt out),是“栈”数据结构的核心思想。
直接上实战代码吧
Queue<Object> objects = Collections.asLifoQueue(new ArrayDeque<>());
objects.add("1");
objects.add("2");
objects.add("3");
System.out.println(objects);
Deque<String> deque = new ArrayDeque<>();
deque.add("1");
deque.add("2");
deque.add("3");
System.out.println(deque);
评价
提供了一些基础的集合操作,不过并不能完全满足业务中的需求,而只能作为补充而已。