private E remove(Entry<E> e) {
if (e == header)
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
e.next = e.previous = null;
e.element = null;
size--;
modCount++;
return result;
}
针对remove(Object)必须执行的操作:
public boolean remove(Object o) {
if (o==null) {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (e.element==null) {
remove(e);
return true;
}
}
} else {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (o.equals(e.element)) {
remove(e);
return true;
}
}
}
return false;
}
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Main {
public static void main(String[] args) {
List<String> myList = new CopyOnWriteArrayList<String>();
myList.add("a");
myList.add("b");
myList.add("c");
// Will print [a, b, c]
System.out.println(myList);
for (String element : myList) {
if (element.equals("a")) {
myList.remove(element);
}
}
// Will print [b, c]
System.out.println(myList);
}
}
9条答案
按热度按时间djmepvbi1#
其他人已经提到了一个有效的观点,通常这不是你从一个集合中
remove
一个对象的方式,但是,在这种情况下,它是好的,因为你break
了循环,一旦你remove
。但是,如果你想在
remove
之后继续迭代,你需要使用迭代器,否则你会得到ConcurrentModificationException
,或者在更普遍的情况下,得到未定义的行为。所以是的,如果你在
remove
之后从foreach
中break
出来,你会没事的。对于那些说这会失败的人,因为你不能修改
foreach
中的集合--只有当你想继续迭代的时候才是这样,这里不是这样,所以这个快捷方式是好的。迭代器检查并抛出
ConcurrentModificationException
,这里,在remove
(符合并发修改条件)之后,您将break
移出循环,迭代器甚至没有机会检测它。最好是在
break
上添加注解,为什么它是绝对必要的,等等,因为如果这个代码后来被修改为在remove
之后继续迭代,它将失败。我将把这个习惯用法看作类似于
goto
(或者更确切地说,标记为break
/continue
):一开始看起来可能是错的,但是如果使用得当,它会使代码更干净。cs7cruho2#
在搜索对象时,最好使用迭代器和它的remove方法,通过迭代集合来删除对象。
1.例如,集合可以是一个链表(在您的例子中,它确实是),其remove方法意味着要重新搜索对象,而搜索的复杂度可能是O(n)。
1.除非使用迭代器的remove方法,否则在remove之后不能继续迭代,现在你正在删除第一个匹配项,将来你可能需要删除所有匹配项,在这种情况下,你必须重写循环。
原则上,我建议放弃增强的for,而使用类似下面的内容:
这样,您就不会对未来可能发生变化的基础列表做出假设。
比较代码,删除迭代器remove调用的最后一个条目(格式化Sun's):
针对remove(Object)必须执行的操作:
zrfyljdw3#
您应该使用
iterator.remove()
:从基础集合中移除迭代器返回的最后一个元素(可选操作)。每次调用next时只能调用一次此方法。如果在迭代过程中以调用此方法以外的任何方式修改了基础集合,则迭代器的行为为未指定。
pgccezyw4#
编辑:事实上,它不会因为断裂而失败。详情见polygenelubricant的回答。
然而,这是一种危险的做法。要在Java中并发地迭代和修改集合,必须使用“ListIterator”对象,并使用迭代器自己的“add()”和“remove()”方法,而不是使用集合上的方法。
您可以在java文档中查找“java.util.Iterator”和“java.util.ListIterator”类
dphi5xsq5#
试试这样的方法:
这是最后几个不能用foreach循环替换Iterator的地方之一。
ljo96ir56#
要避免ConcurrentModifiationException异常,您可以执行以下操作:
或
我更喜欢第一种。处理索引更容易出错,而且迭代器可以有效地实现。第一种建议适用于Iterable,而第二种建议需要一个List。
jogvjijk7#
上面的第二个循环应该稍微改变一下
或
yqyhoc1h8#
CopyOnWriteArrayList
可能就是你要找的。当执行可变操作时,会复制底层数组。这允许在for-each循环中修改列表元素。但要记住,这不是一个链表,可能效率很低。daolsyd09#
在java8中,您可以只使用集合#removeIf
像这样:
列表myList =新数组列表();
(文本-〉对象.为空(文本));//myList.removeIf(对象::为空);