记实践中滥用 LinkedList的小总结 & Collections工具类新认知

记实践中滥用 LinkedList的小总结 & Collections工具类新认知

ArrayList 与 LinkedList

最基本的认知是二者底层数据结构的不同:前者ArrayList基于数组,后者LinkedList基于链表;
其中ArrayList默认大小为10,在容量不足的情况需要扩容。

在业务场景中,如果没有特殊需求只是存储数据,无脑使用ArrayList,如果明确具体大小,最好在初始化时就带有容量,从而避免扩容。相信打过力扣算法的,都对LinkedList不陌生,不论是队列还是栈都可以使用LinkedList来实例化,也是导致笔者滥用的原因,潜意识总觉得是最方便的。回归到两者的底层数据结构,空间上链表比数组要多维护指针

Collections工具类

return null / return new ArrayList<>() -> return Collections.emptyList()

在开发中,对于没有结果的列表返回值,笔者由于自身没有去充分了解,一直直接使用null,这很可能会造成空指针异常;可能也有初级开发者会直接使用new ArrayList<>()的方式去返回。
实际上,在Collectons工具类中,包含了空列表emptyList()、空集合emptyMap()、emptySet等空容器静态内部类,通过阅读源码,不难发现空列表会比一个ArrayList对象减少维护一些类似于容量大小,负载因子等变量;emptyList无需像arrayList一样去维护内部成员变量,顾名思义空列表一定为空,相比 ArrayList既节省资源又达到了防止出现空指针异常的目的。

这里附着上Collections所包含的对于emptyList的定义,继承了抽象list实现相关方法;从代码中也能发现其他与empty相关的对象

  • emptyIterator
  • emptyListIterator
  • emptySpliterator
  • 等等…
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;
        }
    }

其中需要注意的是,返回空列表适用于只读场景,但对于需要对列表进行写场景,仍然需要开发者去附加考虑;
可以使用一个简单的例子进行实践证明,拿到的列表是空列表,而后进行add操作

public static void main(String[] args) {
    
    
        List<String> list = Collections.EMPTY_LIST;
        list.add("test");
        System.out.println(list);
    }

程序运行会报UnsupportedOperationException异常,EmptyList继承AbstractList抽象类,且没有对add方法进行重写,而AbstractList抽象类 的add方法默认实现方法就是抛出该异常。

当然并不是所有关于写操作都会报错,如果是对于返回的列表中的元素进行某些操作的覆盖写操作,则不会出现异常,如以下代码

public static void main(String[] args) {
    
    
        List<String> list = Collections.EMPTY_LIST;
        list.forEach(s -> s.replace('1','2'));
        System.out.println(list);
    }

猜你喜欢

转载自blog.csdn.net/weixin_47407737/article/details/128356894