Java 的 List 实际使用注意要点
最近想自己写一个简单的 Rss 阅读器练手,在阅读 Github 上面的项目 android-rss 时,在 List 的使用上碰到一些不同于入门书籍的代码,并不是很明白意思。之后,不断百度 + Google 终于明白。 代码原文:
|
|
如何返回空列表
空列表不是 null
最好的解释在《Effective Java(第二版)》的第七章第 43 条。 大体意思是: 如果代码需要返回列表,且列表长度有可能为 0,常见的新手(比如我 O_O)的代码:
|
|
这样,会把零长度列表变成了一种特例(null),在使用的时候逻辑就会非常奇怪 —— 必须加上诸如 if (list != null)
这样的判断分支。
这么做无谓地增加了代码地长度,而且调用时容易忘记判断分支导致空指针错误。尤其,当某个库文件这么写地时候,使用者的调用代码会经常出错,因为库使用者经常使用链式调用方式(getList().a().b().c())完成一系列任务。
而且,即使不返回 null 也不代表代码就会出错,比如:
|
|
只要程序员写的是标准的遍历代码,就已经暗含了零长度的边界值判断,不会发生对空列表元素的各种操作。
返回 Collections.emptyList() 而不是 new List()
虽然可以自己新建立一个空的列表并返回,如 return new ArrayList();
。
但这么做并不可取,因为:
- 列表实际是可以修改的,可能会有错误的操作(尤其涉及多线程时)将本该时空列表的结果进行更改,这样很不安全,而且错误难以发现
- 每次返回空列表其实都会重新建立一个对象,但又不会对它内部进行什么有效操作,浪费了资源
为了解决这两个问题,Java 的集合库包含了只读零长度列表的实现,需要的时候调用 Collections.emptyList()
即可。这样的空列表如果调用 get()
方法会抛出异常 IndexOutOfBoundsException
,但是正常的遍历代码不会受到影响,会因零长度而不满足遍历的条件判断。
注意:另外,如果需要对返回的列表指定元素类型,Java 7 及之后可以直接这么使用就好,而 Java 5 和 Java 6 则要声明类型,如:
|
|
如果没有列表元素类型的要求,甚至可以直接使用常量 Collections.EMPTY_LIST
注意加工只读的返回结果
要使用 Collections.unmodifiableList()
加工只读的列表,防止使用时修改了只读列表,如:
|
|
实际工程中经常遇到需要处理只读列表的场景,这样的代码就能很好的防止调用代码修改结果列表,算是防御编程(defensive programming)的良好实践。这样的结果列表就是 Immutable List,是类似 String 的 Immutable 对象。
使用 Immutable 对象有以下的优点:
- 更安全:对不可靠的客户代码库来说,使用它也无法修改数据,可以在未受信任的类库中安全的使用这些对象
- 线程安全:Immutable 对象在多线程下没有竞态条件,可以直接共享
- 更高效:不需要支持可变性, 可以尽量节省空间和时间的开销
- 可以当成常量反复使用:通过静态工厂方法从缓存中取出已经存在的 Immutable 对象,而不是重新创建
但是,也应该注意它的缺点:Immutable 对象无法修改,当处理大量数据时可能会制造大量垃圾(类似 String),需要根据要求谨慎使用。
其他
这样的修改应该发生在代码重构环节,原始编码时可以不予考虑,但一旦要将代码部署到生产环节就必须进行仔细的修改。 另外,《Effective Java》和《重构 —— 改善既有代码的设计》这样的数还是应该好好读读的。
参考: http://stackoverflow.com/questions/5552258/collections-emptylist-vs-new-instance https://my.oschina.net/jasonultimate/blog/166810