JAVA 集合取交集 retainAll 删除元素 removeIf
集合取交集 Collection.retainAll()
两个集合取交集的操作,详见代码:
// 两个集合取交集
public static void main(String[] args) {
List<String> listA = new ArrayList<>();
listA.add("A");
listA.add("B");
listA.add("C");
List<String> listB = new ArrayList<>();
listB.add("C");
listB.add("B");
listB.add("E");
listA.retainAll(listB);
listA.forEach(System.out::println);
}
输出结果:
按条件删除集合中的某些元素 Collection.retainAll()
错误示范:
// 错误示范
public static void main(String[] args) {
List<String> listA = new ArrayList<>();
listA.add("A");
listA.add("B");
listA.add("C");
List<String> listB = new ArrayList<>();
listB.add("C");
listB.add("B");
listB.add("E");
listA.forEach(a -> {
listB.forEach(b -> {
if (a.equals(b)) {
listA.remove(a);
}
});
});
listA.remove("b");
listA.forEach(System.out::println);
}
遍历过程中执行remove方法
定位到ArrayList里面
报错原因:remove方法里面执行了fastRemove,而fastRemove里面执行了modCount++,导致modCount变了
//remove方法里面执行了fastRemove
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
//fastRemove里面执行了modCount++,导致modCount变了
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
解决方案一:迭代器遍历
//迭代器遍历
public static void main(String[] args) {
List<String> listA = new ArrayList<>();
listA.add("A");
listA.add("B");
listA.add("C");
List<String> listB = new ArrayList<>();
listB.add("C");
listB.add("B");
listB.add("E");
for (Iterator<String> it = listA.iterator(); it.hasNext();) {
String o = it.next();
listB.forEach(b -> {
if (o.equals(b)) {
it.remove();
}
});
}
listA.forEach(System.out::println);
}
输出结果:
解决方案二:使用Collection的removeIf方法
removeIf方法源码如下,其实也是用了迭代器
tip:jdk1.8及以后可用,之前的版本没有滴
/**
* Removes all of the elements of this collection that satisfy the given
* predicate. Errors or runtime exceptions thrown during iteration or by
* the predicate are relayed to the caller.
*
* @implSpec
* The default implementation traverses all elements of the collection using
* its {@link #iterator}. Each matching element is removed using
* {@link Iterator#remove()}. If the collection's iterator does not
* support removal then an {@code UnsupportedOperationException} will be
* thrown on the first matching element.
*
* @param filter a predicate which returns {@code true} for elements to be
* removed
* @return {@code true} if any elements were removed
* @throws NullPointerException if the specified filter is null
* @throws UnsupportedOperationException if elements cannot be removed
* from this collection. Implementations may throw this exception if a
* matching element cannot be removed or if, in general, removal is not
* supported.
* @since 1.8
*/
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
具体使用示例:
public static void main(String[] args) {
List<String> listA = new ArrayList<>();
listA.add("A");
listA.add("B");
listA.add("C");
List<String> listB = new ArrayList<>();
listB.add("C");
listB.add("B");
listB.add("E");
listA.removeIf(listB::contains);
listA.forEach(System.out::println);
}
输出结果: