Java Collections的emptyList、EMPTY_LIST详解与使用说明
collections的emptylist、empty_list使用
今天在看大佬写的代码的时候,结果集为空的情况,他返回的不是null,而是:
return collections.empty_list;
我们都知道返回null,很有可能造成空指针异常,可以使用emptylist或empty_list就可以避免这个问题,除非你想捕获这个为空的信息
我们在使用emptylist空的方法返回空集合的时候要注意,这个空集合是不可变的。
空的集合不可以使用add方法,会报unsupportedoperationexception异常,看如下源码:
public void add(int index, e element) { throw new unsupportedoperationexception(); }
空集合对象不可以使用put方法,会报indexoutofboundsexception异常,看如下源码:
public e get(int index) { throw new indexoutofboundsexception("index: "+index); }
但是对于for循环都不会发生异常,如下的示例:
list<string> list1 = collections.emptylist(); for(string s:list1) { } for(int i=0;i<list1.size();i++) { }
上面的两种for循环都可以正常的执行,第一种foreach循环,实际编译之后会变成迭代器的模式,这样我们就好理解为什么可以正常执行;第二种是只调用了size方法,我们可以看到源码直接返回0;
public int size() {return 0;}
emptylist和empty_list的区别,我们看下源码:
/** * the empty list (immutable). this list is serializable. * * @see #emptylist() */ @suppresswarnings("unchecked") public static final list empty_list = new emptylist<>();
/** * returns the empty list (immutable). this list is serializable. * * <p>this example illustrates the type-safe way to obtain an empty list: * <pre> * list<string> s = collections.emptylist(); * </pre> * implementation note: implementations of this method need not * create a separate <tt>list</tt> object for each call. using this * method is likely to have comparable cost to using the like-named * field. (unlike this method, the field does not provide type safety.) * * @see #empty_list * @since 1.5 */ @suppresswarnings("unchecked") public static final <t> list<t> emptylist() { return (list<t>) empty_list; }
我们看到empty_list 是collections类的一个静态常量,而emptylist是支持泛型的。若是不需要泛型的地方可以直接使用 empty_list ,若是需要泛型的地方就需要使用emptylist。
通过上面的分析我们可以很清楚的知道什么时候使用emptylist;collections集合中还有其它的几种空集合emptymap、emptyset,他们的使用方法跟上面的大同小异。
collections.emptylist()使用注意
偶然发现有小伙伴错误地使用了collections.emptylist()方法,这里记录一下。它的使用方式是:
public void run() { ...... list list = buildlist(param); ...... object newnode = getnode(...); list.add(newnode); ...... } public list buildlist(object param) { if (isinvalid(param)) { return collections.emptylist(); } else { ...... } }
buildlist方法中可能会返回一个"空的list",后续还可能往这个list添加元素(或者移除元素),但是没有注意collections.emptylist方法返回的是一个empty_list:
public static final <t> list<t> emptylist() { return (list<t>) empty_list; }
它是一个static final修饰的成员变量,是一个emptylist类的实例:
public static final list empty_list = new emptylist<>();
这个emptylist是一个静态内部类,和arraylist一样继承自abstractlist:
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; } }
可以看到这个emptlist没有重写add方法,并且get方法也是直接抛出一个indexoutofboundsexception异常。既然没有重写add方法,那么看看父类abstractlist中的add方法:
public boolean add(e e) { add(size(), e); return true; } public void add(int index, e element) { throw new unsupportedoperationexception(); }
可以看到直接抛出的unsupportedoperationexception异常。再回到emptylist类中,它对外提供的一些方法也很明显地限制了它的使用范围。
对于collections.emptylist(),或者说collections.empty_list,最好只把它当做一个空列表的标识(可以想象成一个frozen过的空list),不要对其做一些增删改查的操作。如果程序中的一些分支逻辑返回了这种实例,测试的时候又没有覆盖到,在生产环境如果走到了这个分支逻辑,那就麻烦了~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。