参考https://blog.csdn.net/bfboys/article/details/53545855
使用list的时候在倒数第二个元素删除其他元素不会异常
使用set的时候在倒数第一个元素删除其他元素不会异常
不会进入判断
首先,要删除list中为2的元素
List<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for(int i = 0; i < list.size(); ++i){
if(list.get(i) == 2){
list.remove(i);
}
}
System.out.println(list);
这个代码看似正确,也输出了正确的结果,但是如果不只一个2的时候就出问题了
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
输出
[1, 2, 3,4]
为什么,因为当删除第一个2之后,下次循环i成了2对吧,但是因为前一个2被删了,后面的元素向前移,此时第二个2就被跳过了,直接到了3,因此出现了这样的结果。
另一种写法
for(Integer i : list){
if(i == 2){
list.remove(i); //删除的不是i这个下标。。。。。
}
}
结果
Exception in thread “main” java.util.ConcurrentModificationException
实际上这段代码成了
for(Iterator<Integer> it = list.iterator(); it.hasNext();){
Integer i = it.next();
if(i == 2){
list.remove(i);
}
}
list.remove(i);改成it.remove();
for(Iterator<Integer> it = list.iterator(); it.hasNext();){
Integer i = it.next();
if(i == 2){
it.remove();
}
}
为什么会这样呢
因为list是通过size来维护,iterator是却不是
当list调用自身的remove方法之后,iterator并不会感知,就造成了不一致。
list中iterator的源码
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
checkForComodification();
这个就是检查是否一致的函数
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
其中modCount 表示list整个修改次数,expectedModCount表示通过iterator修改的次数,如果2者不想等,就会抛出异常。
//上面用的list.remove(i)抛出异常,因为在使用it.next()的时候,进行检查,
//2者不等抛出了异常
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
上面的remove好像只++expectedModCount, 没有++modCount啊;
其实这个写在了unlink函数之中,看他的源码就可以找到modCount+;。