Java List retainAll 记录坑

描述

我们知道使用List的retainAll方法可以获取两个集合的交集,但是在某些情况下方法的返回值并非我们想象那样。

现象

先看两个例子:

   public static void main(String[] args) {
        List<String> a = new ArrayList<>();
        a.add("READ");
        a.add("DELETE");
        a.add("TTT");
        List<String> b = new ArrayList<>();
        b.add("READ");
        b.add("WRITE");
        System.out.println(b.retainAll(a));
        System.out.println(b);
    }

代码运行结果如下:

这个运行结果是我们想要的结果:方法返回true,b集合中剩下交集的元素。

再看个情况

    public static void main(String[] args) {
        List<String> a = new ArrayList<>();
        a.add("READ");
        a.add("DELETE");
        a.add("TTT");
        List<String> b = new ArrayList<>();
        b.add("READ");
        System.out.println(b.retainAll(a));
        System.out.println(b);
    }

运行结果如下:

 

两个集合有交集"READ",但是运行结果返回的是false 

发现这个结果并不是我们想要的true。

我们来查询下源码:注释中写到只有当这个list发生change的时候,才会return true。

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * @param c collection containing elements to be retained in this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        return batchRemove(c, true, 0, size);
    }

    boolean batchRemove(Collection<?> c, boolean complement,
                        final int from, final int end) {
        Objects.requireNonNull(c);
        final Object[] es = elementData;
        int r;
        // Optimize for initial run of survivors
        for (r = from;; r++) {
            if (r == end)
                return false;
            if (c.contains(es[r]) != complement)
                break;
        }
        int w = r++;
        try {
            for (Object e; r < end; r++)
                if (c.contains(e = es[r]) == complement)
                    es[w++] = e;
        } catch (Throwable ex) {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            System.arraycopy(es, r, es, w, end - r);
            w += end - r;
            throw ex;
        } finally {
            modCount += end - w;
            shiftTailOverGap(es, w, end);
        }
        return true;
    }

下面我们来debug测试下     

       当我们debug到batchRemove的第一个for循环的时候,发现在第二次循环的时候就直接return了false。

       而只有当c中有不包含es的元素的时候,代码才会继续往下走,只要不抛异常就会返回true,从而我们知道方法的返回值对我们取两个集合的交集并没有太大作用。

结论

        方法的返回值仅供参考该list是否发生过元素的remove,而不应该作为两个集合是否有交集的依据。可以通过判断b  list中元素个数是否大于1来判断是否有交集。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值