看如下代码:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String name : list) {
System.out.println(name);
if ("ccc".equals(name)) {
list.remove(name);
}
}
}
看一下抛出的异常信息:
remove()方法并不会抛出异常,抛出异常的是Itr的next方法!!但是remove()方法会导致Itr.next()发生异常。
Itr是ArrayList的一个内部迭代器类,增强for实际上调用的就是这个迭代器的代码!看下这两个方法的代码:
public boolean remove(Object o) {
modCount++;//就是这个变量(修改次数)和异常的发生有密切关系!!
...
}
再看下Itr的代码:
private class Itr implements Iterator<E> {
int expectedModCount = modCount;//这里是初始化赋值
Itr() {}
public E next() {
checkForComodification();
...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
当使用增强for遍历时,会new Itr(),在初始化对象的时候expectedModCount就已经被modCount初始化确定了!!所以调用了remove()方法会使modCount++。导致expectedModCount、modCount不相等!这样再取下一个元素next()的时候,就会被检查出不相等,导致程序抛出ConcurrentModificationException异常。
补充:
1、我们直接使用ArrayList的迭代器,其实用的也是Itr类对象。所以直接用增强for会更方便!
Iterator<String> iterator = list.iterator();
public Iterator<E> iterator() {
return new Itr();
}
2、使用增强for遍历时,删除list中的倒数第二个元素,不会抛出ConcurrentModificationException异常。
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String name : list) {
System.out.println(name);
if ("bbb".equals(name)) {
list.remove(name);
}
}
for(String name:list){
System.out.println(name);
}
正常运行!打印:
aaa
bbb
aaa
ccc
原因:
remove("bb");以后,程序认为已经遍历完成,hasNext()返回false,所以不会再执行next()去取得下一个元素"cc"。所以不会检查expectedModCount、modCount是否相等,故不会抛出异常。
上面的增强for的使用,相当于下面迭代器的使用:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
if("bbb".equals(name)){
list.remove(name);
}
}
下面看下为什么删除了倒数第二个元素后hasNext()会返回false,删除最后一个元素后hasNext却返回true!
public E remove(Object o) {
...
elementData[--size] = null; // clear to let GC do its work
...
}
public boolean hasNext() {
//cursor是当前元素的index
return cursor != size;
}
不难发现,remove(倒是第二个);的时候,--size导致cursor和size相等,所以hasNext会返回false。而remove(最后一个);会导致cursor比size大1,所以cursor!=size会返回true,即hasNext返回true。最后一个都删除了,哪里还有下一个,理所当然要抛异常了!
仅学习使用
原文作者:
看如下代码:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String name : list) {
System.out.println(name);
if ("ccc".equals(name)) {
list.remove(name);
}
}
}
看一下抛出的异常信息:
remove()方法并不会抛出异常,抛出异常的是Itr的next方法!!但是remove()方法会导致Itr.next()发生异常。
Itr是ArrayList的一个内部迭代器类,增强for实际上调用的就是这个迭代器的代码!看下这两个方法的代码:
public boolean remove(Object o) {
modCount++;//就是这个变量(修改次数)和异常的发生有密切关系!!
...
}
再看下Itr的代码:
private class Itr implements Iterator<E> {
int expectedModCount = modCount;//这里是初始化赋值
Itr() {}
public E next() {
checkForComodification();
...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
当使用增强for遍历时,会new Itr(),在初始化对象的时候expectedModCount就已经被modCount初始化确定了!!所以调用了remove()方法会使modCount++。导致expectedModCount、modCount不相等!这样再取下一个元素next()的时候,就会被检查出不相等,导致程序抛出ConcurrentModificationException异常。
补充:
1、我们直接使用ArrayList的迭代器,其实用的也是Itr类对象。所以直接用增强for会更方便!
Iterator<String> iterator = list.iterator();
public Iterator<E> iterator() {
return new Itr();
}
2、使用增强for遍历时,删除list中的倒数第二个元素,不会抛出ConcurrentModificationException异常。
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String name : list) {
System.out.println(name);
if ("bbb".equals(name)) {
list.remove(name);
}
}
for(String name:list){
System.out.println(name);
}
正常运行!打印:
aaa
bbb
aaa
ccc
原因:
remove("bb");以后,程序认为已经遍历完成,hasNext()返回false,所以不会再执行next()去取得下一个元素"cc"。所以不会检查expectedModCount、modCount是否相等,故不会抛出异常。
上面的增强for的使用,相当于下面迭代器的使用:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
if("bbb".equals(name)){
list.remove(name);
}
}
下面看下为什么删除了倒数第二个元素后hasNext()会返回false,删除最后一个元素后hasNext却返回true!
public E remove(Object o) {
...
elementData[--size] = null; // clear to let GC do its work
...
}
public boolean hasNext() {
//cursor是当前元素的index
return cursor != size;
}
不难发现,remove(倒是第二个);的时候,--size导致cursor和size相等,所以hasNext会返回false。而remove(最后一个);会导致cursor比size大1,所以cursor!=size会返回true,即hasNext返回true。最后一个都删除了,哪里还有下一个,理所当然要抛异常了!
注:本文为转载博文,仅供个人学习使用
原文作者:写代码砌砖头
原文链接:https://blog.csdn.net/river66/article/details/88873872