ArrayList删除倒数第二个元素不报ConcurrentModificationException原因-----阿里开发手册
2017-10-03 15:47
561 查看
最近看阿里的开发手册发现当迭代ArrayList时删除ArrayList的倒数第二个元素是不会报ConcurrentModificationException异常,为此个人写了一下测试代码去ArrayList源码查找了一下原因,在说明前个人觉得还是需要先介绍一下List的foreach过程。
Java在通过foreach遍历集合列表时,会先为列表创建对应的迭代器,并通过调用迭代器的hasNext()函数判断是否含下一个元素,若有则调用iterator.next()获取继续遍历,没有则结束遍历。即通过String each:list遍历相当于在List中先创建一个迭代器,然后进行if(iterator.hasNext)判断是否还含有元素,有则进行each = iterator.next()进行赋值遍历。
该文章ArrayList移除元素时涉及的方法:
elementData为列表用于存储数据的数组,而modCount++为列表结构的修改次数,删除元素不为null时看remove(Object o)中的第二个循环,由fastRemove(int index)可以看出列表每次删除元素时修改此时modCount都会自增1。
ArrayList的iterator方法(Itr实现Iterator接口,是ArrayList的内部类,含iterator()方法的集合类都会返回相应的Iterator实现类):
该文章涉及的ArrayList迭代器Itr的主要内容如下(省略remove与forEachRemaining方法):
由Itr中的checkForComodification()方法可以看出当列表的修改次数(默认值为0)与希望的修改次数(0)不相等时都会抛出ConcurrentModificationException异常,而cursor为下一个返回值的列表索引,如下例中遍历到"f"时cursor为5等于列表size 5。
源码看到这应该清楚的知道遍历list时进行删除抛出错误的原因是因为modCount != expectedModCount,而删除倒数第二个不抛错的原因就在于迭代器获取元素前的hasNext()判断,当遍历到倒数第二个元素并删除该元素时将使列表的size-1并等于cursor,此时hasNext()返回false所以不再调用next()方法调用checkForComodification()进行修改验证。
以下是个人的测试代码,由于删除的元素位于ArrayList的倒数第二个,所有并不会抛并发修改异常:
Java在通过foreach遍历集合列表时,会先为列表创建对应的迭代器,并通过调用迭代器的hasNext()函数判断是否含下一个元素,若有则调用iterator.next()获取继续遍历,没有则结束遍历。即通过String each:list遍历相当于在List中先创建一个迭代器,然后进行if(iterator.hasNext)判断是否还含有元素,有则进行each = iterator.next()进行赋值遍历。
该文章ArrayList移除元素时涉及的方法:
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }
elementData为列表用于存储数据的数组,而modCount++为列表结构的修改次数,删除元素不为null时看remove(Object o)中的第二个循环,由fastRemove(int index)可以看出列表每次删除元素时修改此时modCount都会自增1。
ArrayList的iterator方法(Itr实现Iterator接口,是ArrayList的内部类,含iterator()方法的集合类都会返回相应的Iterator实现类):
public Iterator<E> iterator() { return new Itr(); }
该文章涉及的ArrayList迭代器Itr的主要内容如下(省略remove与forEachRemaining方法):
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
由Itr中的checkForComodification()方法可以看出当列表的修改次数(默认值为0)与希望的修改次数(0)不相等时都会抛出ConcurrentModificationException异常,而cursor为下一个返回值的列表索引,如下例中遍历到"f"时cursor为5等于列表size 5。
源码看到这应该清楚的知道遍历list时进行删除抛出错误的原因是因为modCount != expectedModCount,而删除倒数第二个不抛错的原因就在于迭代器获取元素前的hasNext()判断,当遍历到倒数第二个元素并删除该元素时将使列表的size-1并等于cursor,此时hasNext()返回false所以不再调用next()方法调用checkForComodification()进行修改验证。
以下是个人的测试代码,由于删除的元素位于ArrayList的倒数第二个,所有并不会抛并发修改异常:
package per.test.list; import com.google.common.collect.Lists; import org.junit.Test; import java.util.List; import java.util.Objects; /** * 创建人:Wilson * 描述: * 创建日期:2017/10/3 */ public class ListTest { @Test public void listRemoveTest() { List<String> list = Lists.newArrayList("a", "b", "c", "d", "e", "f"); for (String each : list) { if(Objects.equals(each,"e")){ list.remove(each); } } } }
相关文章推荐
- 遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置
- 循环List删除元素抛ConcurrentModificationException异常原因分析
- 遍历集合时删除元素,抛出java.util.ConcurrentModificationException的解决办法
- arraylist 遇到java.util.ConcurrentModificationException真正原因。
- 遍历集合时删除元素,抛出java.util.ConcurrentModificationException的解决办法
- ArrayList引起的ConcurrentModificationException 异常原因及解决方法
- java set 删除元素 java.util.ConcurrentModificationException
- JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常
- 从ArrayList中删除对象报java.util.ConcurrentModificationException异常解决
- Hashtable 删除元素, 抛出异常 java.util.ConcurrentModificationException
- Java中集合删除元素时候关于ConcurrentModificationException的迷惑点
- ArrayList迭代,删除list中内容出现ConcurrentModificationException
- 关于迭代集合同时删除元素报错的问题java.util.ConcurrentModificationException
- JAVA集合中删除元素时的java.util.ConcurrentModificationException
- 从ArrayList中删除对象报java.util.ConcurrentModificationException异常解决
- 从ArrayList中删除对象报java.util.ConcurrentModificationException异常解决
- java.util.ConcurrentModificationException---用迭代器遍历Map时删除其中元素出现异
- List删除元素报Exception in thread "main" java.util.ConcurrentModificationException异常,或数据删除不完整
- 集合遍历时删除元素异常(ConcurrentModificationException)分析
- ConcurrentModificationException产生原因及解决方法