1.概述
2.好处
- 如果你想 new 一个空的 List ,而这个 List 以后也不会再添加元素,那么就用
Collections.emptyList()
好了。new ArrayList()
或者new LinkedList()
在创建的时候有会有初始大小,多少会占用一内存。
每次使用都new 一个空的list集合,浪费就积少成多,浪费就严重啦,就不好啦 - 为了编码的方便。
比如说一个方法返回类型是List
,当没有任何结果的时候,返回null
,有结果的时候,返回list
集合列表。
那样的话,调用这个方法的地方,就需要进行null
判断。使用emptyList
这样的方法,可以方便方法调用者。返回的就不会是null
,省去重复代码。
2.1 不占用内存
emptyList不需要占用内存,而ArrayList每次new都会在堆中开辟内存空间存放对象,我们先通过代码验证一下
public class ListTest {
private static final int printCount = 10000;
public static void main(String[] args) {
long freeMemory = Runtime.getRuntime().freeMemory();
System.out.println("freeMemory: " + freeMemory);
for (int i = 0; i < printCount; i++) {
List newList = new ArrayList();
}
long freeMemoryNew=Runtime.getRuntime().freeMemory();
System.out.println("freeMemory use: "+(freeMemory-freeMemoryNew));
for(int i = 0;i < printCount; i++){
List emptyList = Collections.emptyList();
}
long freeMemoryEmpty = Runtime.getRuntime().freeMemory();
System.out.println("freeMemory use: "+(freeMemoryNew-freeMemoryEmpty));
}
}
此时我们看一下执行结果
Connected to the target VM, address: '127.0.0.1:63534', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:63534', transport: 'socket'
freeMemory: 253398816
freeMemory use: 1430376
freeMemory use: 0
我们可以看出new ArrayList
执行一万次会消耗1430376KB
内存,而Collections.emptyList
不会消耗内存。
那有人会说emptyList不也是new EmptyList()
吗?
其实我们再仔细看下源码就发现emptyList是一个static变量,只会初始化一次,所以后续使用不会再初始化对象
。此时我们可以得出结论,emptyList不占用内存,但是无法执行add等方法,new ArrayList()占用内存,但是会初始化对象数组,可以执行add等方法。
3.注意
这个空的集合是不能调用.add()
,添加元素的。因为直接报异常。因为源码就是这么写的:直接抛异常。
Collections里面没这么写,但是EmptyList继承了AbstractList这个抽象类,里面简单实现了部分集合框架的方法。
这里面的add方法最后调用的方法体,就是直接抛异常。
throw new UnsupportedOperationException();
这么解释add报异常就对啦。
4.源码
下面简单看下这个源码:
/**
* Collections 类里面的方法如下,一步步往下看就是啦
*/
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
//。。。。。
/**
* Collections 类里面的方法如下,一步步往下看就是啦
*/
public static final List EMPTY_LIST = new EmptyList<>();
//。。。。。
/**
* Collections里面的一个静态内部类
*/
private static class EmptyList<E> extends AbstractList<E> implements RandomAccess, Serializable {
private static final long serialVersionUID = 8842843931221139166L;
public Iterator<E> iterator() {
return emptyIterator();
}
public ListIterator<E> listIterator() {
return emptyListIterator();
}
public int size() {
return 0;}
public boolean isEmpty() {
return true;}
public boolean contains(Object obj) {
return false;}
public boolean containsAll(Collection<?> c) {
return c.isEmpty(); }
public Object[] toArray() {
return new Object[0]; }
public <T> T[] toArray(T[] a) {
if (a.length > 0)
a[0] = null;
return a;
}
public E get(int index) {
throw new IndexOutOfBoundsException("Index: "+index);
}
public boolean equals(Object o) {
return (o instanceof List) && ((List<?>)o).isEmpty();
}
public int hashCode() {
return 1; }
// Preserves singleton property
private Object readResolve() {
return EMPTY_LIST;
}
}
除了这个emptyList,之外,还有类似的,emptyMap,emptySet等等。具体看下图,都是一个套路。
5.案例
参考:https://blog.csdn.net/m0_46309515/article/details/107161340