概述
本文翻译自:Calling remove in foreach loop in Java [duplicate]
This question already has an answer here: 这个问题已经在这里有了答案:
- Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop 24 answers 遍历Collection,在循环中删除对象时避免ConcurrentModificationException 24答案
In Java, is it legal to call remove on a collection when iterating through the collection using a foreach loop? 在Java中,使用foreach循环遍历集合时,对集合调用remove是合法的吗? For instance: 例如:
List<String> names = ....
for (String name : names) {
// Do something
names.remove(name).
}
As an addendum, is it legal to remove items that have not been iterated over yet? 作为附录,删除尚未迭代的项是否合法? For instance, 例如,
//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
// Do something
while (names.remove(name));
}
#1楼
参考:https://stackoom.com/question/51Hm/在Java中的foreach循环中调用remove
#2楼
You don't want to do that. 你不想那样做。 It can cause undefined behavior depending on the collection. 可能会导致不确定的行为,具体取决于集合。 You want to use an Iterator directly. 您想直接使用Iterator 。 Although the for each construct is syntactic sugar and is really using an iterator, it hides it from your code so you can't access it to call Iterator.remove
. 尽管for每个构造都是语法糖,并且确实使用了迭代器,但它会将其隐藏在代码中,因此您无法访问它来调用Iterator.remove
。
The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method. 如果在迭代进行过程中以其他方式(而不是通过调用此方法)修改了基础集合,则未指定迭代器的行为。
Instead write your code: 而是编写您的代码:
List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
// Do something
it.remove();
}
Note that the code calls Iterator.remove
, not List.remove
. 请注意,该代码调用Iterator.remove
,而不是List.remove
。
Addendum: 附录:
Even if you are removing an element that has not been iterated over yet, you still don't want to modify the collection and then use the Iterator
. 即使您要删除尚未迭代的元素,您仍然不想修改集合,然后使用Iterator
。 It might modify the collection in a way that is surprising and affects future operations on the Iterator
. 它可能以令人惊讶的方式修改集合,并影响Iterator
上的未来操作。
#3楼
To safely remove from a collection while iterating over it you should use an Iterator. 要在迭代集合时安全地从集合中删除,您应该使用迭代器。
For example: 例如:
List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String s = i.next(); // must be called before you can call i.remove()
// Do something
i.remove();
}
From the Java Documentation : 从Java文档 :
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. 此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间以任何方式对列表进行结构修改,除非通过迭代器自己的remove或add方法,否则迭代器将抛出ConcurrentModificationException。 Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. 因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险。
Perhaps what is unclear to many novices is the fact that iterating over a list using the for/foreach constructs implicitly creates an iterator which is necessarily inaccessible. 对于许多新手而言,也许不清楚的是,使用for / foreach构造对列表进行迭代会隐式创建一个迭代器,该迭代器必不可少。 This info can be found here 该信息可以在这里找到
#4楼
The java design of the "enhanced for loop" was to not expose the iterator to code, but the only way to safely remove an item is to access the iterator. “增强的循环”的java设计是不向代码公开迭代器,但是安全删除项目的唯一方法是访问迭代器。 So in this case you have to do it old school: 因此,在这种情况下,您必须在旧学校学习:
for(Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
//Do Something
i.remove();
}
If in the real code the enhanced for loop is really worth it, then you could add the items to a temporary collection and call removeAll on the list after the loop. 如果在真正的代码中增强的for循环确实值得,那么您可以将项目添加到临时集合中,并在循环后调用列表上的removeAll。
EDIT (re addendum): No, changing the list in any way outside the iterator.remove() method while iterating will cause problems. 编辑(补充):否,在迭代时以iterator.remove()方法之外的任何方式更改列表都会导致问题。 The only way around this is to use a CopyOnWriteArrayList, but that is really intended for concurrency issues. 解决此问题的唯一方法是使用CopyOnWriteArrayList,但这实际上是针对并发问题的。
The cheapest (in terms of lines of code) way to remove duplicates is to dump the list into a LinkedHashSet (and then back into a List if you need). 删除重复项的最便宜的方法(就代码行而言)是将列表转储到LinkedHashSet中(如果需要,再转回到List中)。 This preserves insertion order while removing duplicates. 这样可以保留插入顺序,同时删除重复项。
#5楼
那些说除了通过Iterator不能安全地从集合中删除项目的说法并不完全正确,您可以使用ConcurrentHashMap等并发集合之一来安全地进行删除。
#6楼
for (String name : new ArrayList<String>(names)) {
// Do something
names.remove(nameToRemove);
}
You clone the list names
and iterate through the clone while you remove from the original list. 从原始列表中删除列表names
时,您将对其进行克隆并对其进行遍历。 A bit cleaner than the top answer. 比最佳答案要干净一点。
最后
以上就是阳光天空为你收集整理的在Java中的foreach循环中调用remove的全部内容,希望文章能够帮你解决在Java中的foreach循环中调用remove所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复