public class Alpha {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("a");
al.add("b");
al.add("c");
al.add("d");
al.add("e");
Iterator<String> itr = al.listIterator();
while(itr.hasNext()){
al.remove("d"); // Throws a Concurrent Modification @ this line
if(itr.next().equals("d")){
//itr.remove();
al.remove("d"); // No error on this line
}
}
System.out.println(al);
}
}
换句话说,如果将“al.remove(”d“)放在if构造内部,则不会抛出ConcurrentModificationException,而在同一行代码中,如果放在if -Construct之外则抛出异常。解释!
答案 0 :(得分:2)
这是因为当您使用itr.next()
获取下一个元素时,它将check for modification并检查集合的大小是否已更改。那时if (modCount != expectedModCount)
条件将成为现实。虽然hasNext()方法仅基于当前光标点返回true或false。
如果你愿意,itr.next()
然后在列表上调用remove,那么它也会更新expectedModCount
变量。检查Arraylist迭代器的remove方法。
答案 1 :(得分:0)
副本: Iterating through a list, avoiding ConcurrentModificationException when removing in loop Removing items from a collection in java while iterating over it
简单地说,你无法在迭代中删除元素。
答案 2 :(得分:0)
了解如何实现ArrayList
迭代器:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
因此它检查并发修改,使用公共ArrayList remove方法删除元素,并增加列表修改的计数器,以便在下一次迭代时不会抛出ConcurrentModificationException。
答案 3 :(得分:0)
就像你正在修改当前由其他人使用的文件(这里是ArrayList)(这里是迭代循环)。
答案 4 :(得分:0)
while(itr.hasNext()){
if(itr.next().equals("d"))
{
//itr.remove();
al.remove("d"); // No error on this line
}
}
System.out.println(al);
使用这行代码。希望这会有所帮助
答案 5 :(得分:0)
我添加了一行(第13行)和一些注释行号(第18行,第19行和第21行)。
现在,并没有在第18行抛出ConcurrentModidificationexception,但它在第19行抛出。但是,由于第18行的执行,它被抛出。
此外,我相信您正在使用第18行和第18行的代码。一次一个21。它们不会同时出现在您的代码中。
import java.util.*;
public class HelloWorld{
public static void main(String []args){
ArrayList<String> al = new ArrayList<String>();
al.add("a");
al.add("b");
al.add("c");
al.add("d");
al.add("e");
al.add("f"); // line 13
Iterator<String> itr = al.listIterator();
while(itr.hasNext()){
al.remove("d"); // line 18
if(itr.next().equals("d")){ // line 19
//itr.remove();
al.remove("d"); // line 21
}
}
System.out.println(al);
}
}
让评论第13行。所以这基本上是你的代码,带有一些额外的评论。
如果我们检查迭代器的next()的实现,我们就知道它检查了一开始的任何修改(从而抛出了CoMo)。之后它只返回元素。
因此,如果我们在第18行没有使用迭代器的情况下从列表中删除该元素,则会在next()调用之后检测到该元素。但是如果在next()方法之后删除元素(在第21行;第18行被注释),则仅在后续的next()中检测到CoMo。在您的情况下会发生的是我们在打印&#39; 后耗尽了元素。所以我们从未执行过后续的next(),也没有得到异常。
现在,如果我们取消注释第13行(添加一个新元素),那么我们将在第19行得到ConcurrentModidificationexception,即当执行next next()时。这证明我们将获得CoMo Exception,它只是我们将在一次迭代后得到它。
答案 6 :(得分:0)
正如@VimalBera在前面的回答中指出的那样:在itr.next()
上调用remove之前,你必须使用List
获取下一个元素。
但是,我发现有一些替代方法更适合这个用例。第一个是只是在删除元素时使用迭代器:
public static void main(String[] args) {
List<String> al = new ArrayList<>();
al.add("a");
al.add("b");
al.add("c");
al.add("d");
al.add("e");
for (Iterator<String> itr = al.listIterator(); itr.hasNext(); ) {
String s = itr.next();
if ("d".equals(s)) {
itr.remove();
}
}
System.out.println(al);
}
请注意,使用for
- 循环而不是while
- 循环。这会将迭代器的范围缩小到循环本身(这很好,总是尽量保持范围尽可能窄)。
另一种方法是使用 Java 8 Streams,尤其是filter
方法。但是,这会创建一个全新的列表,并不会真正修改基础列表,但它提供了一个非常好的编程模型。
public static void main(String[] args) {
List<String> al = Arrays.asList("a", "b", "c", "d", "e");
List<String> filtered = al.stream()
.filter(s -> !s.equals("d"))
.collect(Collectors.toList());
System.out.println(filtered);
}
使用这种方法,您显然会获得新列表的额外开销,但您可以获得,您可以将列表视为不可变的,这将在多线程环境中很好地工作。