Java List retainAll 记录坑
List的retainAll方法返回值,并非我们认知的那样,判断两个集合是否有交集不能简单通过返回值来判断,而要用调用者的元素个数是否大于1来判断。
·
描述
我们知道使用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来判断是否有交集。
更多推荐
已为社区贡献1条内容
所有评论(0)