Java踩坑之List的removeAll方法

8 篇文章 0 订阅

摘自:https://www.zhaochao.top/article/182

最近在公司写东西,发现List的removeAll方法报错 Demo代码如下:

        List<Long> ids1 = Arrays.asList(1L, 3L, 2L);
        List<Long> ids2 = Collections.singletonList(2L);
        List<Long> ids3 = new ArrayList<>();
        ids3.add(1L);
        ids3.add(2L);
        List<Long> ids = new ArrayList<>();
        ids.add(2L);
        System.out.println("==== 001");
        ids1.removeAll(ids); // 这一步会报错
        System.out.println("==== 002");
        ids2.removeAll(ids); // 这一步也会报错
        System.out.println("==== 003");
        ids3.removeAll(ids);

001报错的原因是:Arrays.asList 返回的List是自己内部实现的ArrayList 而不是util下的ArrayList对象

    /**
     * Returns a fixed-size list backed by the specified array.  (Changes to //明确指出 返回的是固定大小的list
     * the returned list "write through" to the array.)  This method acts
     * as bridge between array-based and collection-based APIs, in
     * combination with {@link Collection#toArray}.  The returned list is
     * serializable and implements {@link RandomAccess}.
     *
     * <p>This method also provides a convenient way to create a fixed-size
     * list initialized to contain several elements:
     * <pre>
     *     List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
     * </pre>
     *
     * @param <T> the class of the objects in the array
     * @param a the array by which the list will be backed
     * @return a list view of the specified array
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }
        ...... //看的出来,这个list是可以修改的 但是要通过set方法
    }

所以调用removeAll方法的时候 会调用AbstractList的父类AbstractCollection的removeAll方法:

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<?> it = iterator();
        while (it.hasNext()) {
            if (c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

ArrayList是数组 在循环的时候删除元素 一定会出现问题

 

002报错的原因是与001类似:Collections.singletonList的返回值SingletonSet也是自己的内部类

    /**
     * Returns an immutable list containing only the specified object. // 返回不可变的list
     * The returned list is serializable.
     *
     * @param  <T> the class of the objects in the list
     * @param o the sole object to be stored in the returned list.
     * @return an immutable list containing only the specified object.
     * @since 1.3
     */
    public static <T> List<T> singletonList(T o) {
        return new SingletonList<>(o);
    }
   private static class SingletonList<E>
        extends AbstractList<E>
        implements RandomAccess, Serializable {

        private static final long serialVersionUID = 3093736618740652951L;

        private final E element;

        SingletonList(E obj)                {element = obj;}

        public Iterator<E> iterator() {
            return singletonIterator(element);
        }

        public int size()                   {return 1;}

        public boolean contains(Object obj) {return eq(obj, element);}

        public E get(int index) {
            if (index != 0)
              throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
            return element;
        }

        // Override default methods for Collection
        @Override
        public void forEach(Consumer<? super E> action) {
            action.accept(element);
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void sort(Comparator<? super E> c) {
        }
        @Override
        public Spliterator<E> spliterator() {
            return singletonSpliterator(element);
        }
    }
    // 可以看出 这个list是一个只读的list 并未对外提供编辑方法

    同样会调用AbstractCollection的removeAll方法

    

    003是我new的ArrayList对象,会调用自己内部重写的removeAll方法,针对数组重写了删除方法,不会出问题,解决001、002的问题 最简单的办法可以用new ArrayList()包一层就ok了!

 

    究其原因还是自己对源码的研究不足!

更多技术资源请访问:https://www.zhaochao.top/articles

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值