今天学学 Java 中如何创建一个空集合以及空集合的一些使用场景和相关的坑. 你可能会问, 这好像没有什么好讲的, 空集合不就是 new 一个嘛, 也就是像
new ArrayList<String>()
这样创建一个不久行了吗? 其实这也是一种创建空集合的方法, 但今天小编讲下通过另外一种方式创建空集合, 以及两种方式之间的差异.
一, 通过
Collections.emptyList()
创建空集合
Java 集合工具类中提供了一系列创建集合的静态方法, 其中包括创建线程同步相关的
Collections.synchronizedXXX()
方法, 空集合相关的
Collections.emptyXXX()
方法. 通过这种方式创建的空集合, 既然是空的, 就不允许你往集合中添加元素和删除元素, 也就是不能调用相应 add() 和 remove() 方法, 我先来看看 Collections 类创建空集合的部分源代码:
- public static final List EMPTY_LIST = new EmptyList<>();
- ......
- public static final <T> List<T> emptyList() {
- return (List<T>) EMPTY_LIST;
- }
你会发现上面的 emptyList() 方法默认返回的是前面的静态变量 EMPTY_LIST, 你可能会说, 既然 EMPTY_LIST 是 static 的, 那我直接通过
Collections.EMPTY_LIST
获取不就好了, 没错, 这样做也可以, 只不过在某些需要泛型的场景下, 调用 emptyList() 方法提供了相应的泛型支持.
那为什么这种方式不能添加和移除元素呢? 我们来看看 EmptyList 内部类是怎么定义的:
- // 继承自 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; }
- @Override
- public boolean removeIf(Predicate<? super E> filter) {
- Objects.requireNonNull(filter);
- return false;
- }
- @Override
- public void replaceAll(UnaryOperator<E> operator) {
- Objects.requireNonNull(operator);
- }
- @Override
- public void sort(Comparator<? super E> c) {}
- // Override default methods in Collection
- @Override
- public void forEach(Consumer<? super E> action) {
- Objects.requireNonNull(action);
- }
- @Override
- public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
- // Preserves singleton property
- private Object readResolve() {
- return EMPTY_LIST;
- }
- }
从上面的源代码中我们可以发现 EmptyList 类并没有重写父类相应的 add() 或者 remove() 方法, 那么当调用空集合的 add() 方法时将默认调用 AbstractList 的 add() 方法, 行, 那么我们来看看父类 AbstractList 的 add() 方法是怎么实现的:
- public void add(int index, E element) {
- throw new UnsupportedOperationException();
- }
- public E remove(int index) {
- throw new UnsupportedOperationException();
- }
很遗憾, 父类直接给你抛出
UnsupportedOperationException
异常, 所以, 小编认为, 通过 Collections 创建的空集合不能添加或删除元素也是合情合理的, 因为是空集合嘛, 空, 那为啥还要有添加删除操作. 下面说说这种方式的使用场景.
二, 简单使用场景
web 开发中经常使用 rest + json 的技术组合来进行前后端交互, 那么当前端调用一个接口时, 接口有可能需要返回一个空的集合给到前端, 比如你根据某个条件查数据库得不到数据时, 那么此时
Collections.emptyXXX()
就非常合适了, 因为使用 new ArrayList() 的初始化还会占用相关的资源.
为了说明调用 add() 方法会抛出异常, 下面写个小测试:
- public class RemoveIfTest {
- private static List<Object> list = Collections.emptyList();
- public static void main(String[] args) {
- list.add("one1");
- list.add("one2");
- list.add(1);
- list.add(2);
- list.add(new Object());
- System.err.println(Arrays.toString(list.toArray()));
- }
- }
程序输出:
- Exception in thread "main" java.lang.UnsupportedOperationException
- at java.util.AbstractList.add(Unknown Source)
- at java.util.AbstractList.add(Unknown Source)
- at com.example.RemoveIfTest.main(RemoveIfTest.java:17)
三, 总结
总的来说, 对于如何创建空集合的问题我们不需要纠结, 重要的我们要记住通过
Collections.emptyXXX()
创建的空集合不能执行添加删除操作以及其中的原理, 避免以后犯错, 不过其实即使你使用错了, 调试几遍你的代码估计也就会把问题发现出来, 只不过这篇文章能帮你你省去这个发现 bug 的过程啦!
来源: https://juejin.im/post/5b29fdd16fb9a00e65266550