java list remove报错_java list中删除元素用remove()报错的fail-fast机制原理以及解决方案...

java list中删除元素用remove()报错的fail-fast机制原理以及解决方案

现在有一个list,有6个元素,值分别是1、5、5、8、5、10,现需要删除值为5的元素

第一种

import java.util.ArrayList;

import java.util.List;

public class ListRemove1 {

public static void main(String args[]) {

List list = new ArrayList();

list.add(1);

list.add(5);

list.add(5);

list.add(8);

list.add(5);

list.add(10);

for (int j = 0; j < list.size(); j++) {

if (list.get(j) == 5) {

list.remove(j);

}

}

outputList(list);

}

private static void outputList(List list) {

for (int i = 0; i < list.size(); i++) {

System.out.print(list.get(i)+" ");

}

}

}运行结果

1    5    8    10

这结果显然不是我们的预期,我们是希望删除List中所有为5的元素,但输出结果中却出现了5,这是因为在i等于1时,删除了List中的index为1的元素5,这时候list为[1,5,8,5,10], 但接下来,i递增后,等于2,在list.get(i)时,取出来的结果就成为了8了,也就是说随着list元素的删除,index是随之变化的,这就是其中的陷阱

第二种

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

public class ListRemove2 {

public static void main(String args[]) {

List list = new ArrayList();

list.add(1);

list.add(5);

list.add(5);

list.add(8);

list.add(5);

list.add(10);

/*

for (int i1 : list) {

if (i1 == 5) {

list.remove(i1);

}

}

*/

Iterator iterator = list.iterator();

while(iterator.hasNext()){

if(iterator.next() == 5){

list.remove(5);

}

}

outputList(list);

}

private static void outputList(List list) {

for (int i = 0; i < list.size(); i++) {

System.out.print(list.get(i)+" ");

}

}

} 上面代码不管用增强for循环还是用Iterator遍历list,用list.remove()方法都报下面的错误:

2e1caae12d646db32b54f756e6f110dc.png

之所以报上面的错误是因为发生了fail-fast 事件。

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

1.报ConcurrentModificationException异常的原因

ConcurrentModificationException是在操作Iterator时抛出的异常,ArrayList的Iterator是在父类AbstractList.java中实现的,具体源码:

public abstract class AbstractList extends AbstractCollection implements List {

public Iterator iterator() {

return new Itr();

}

private class Itr implements Iterator {

/**

* Index of element to be returned by subsequent call to next.

*/

int cursor = 0;

/**

* Index of element returned by most recent call to next or

* previous. Reset to -1 if this element is deleted by a call

* to remove.

*/

int lastRet = -1;

/**

* The modCount value that the iterator believes that the backing

* List should have. If this expectation is violated, the iterator

* has detected concurrent modification.

*/

int expectedModCount = modCount;

public boolean hasNext() {

return cursor != size();

}

public E next() {

checkForComodification();

try {

E next = get(cursor);

lastRet = cursor++;

return next;

} catch (IndexOutOfBoundsException e) {

checkForComodification();

throw new NoSuchElementException();

}

}

public void remove() {

if (lastRet == -1)

throw new IllegalStateException();

checkForComodification();

try {

AbstractList.this.remove(lastRet);

if (lastRet < cursor)

cursor--;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException e) {

throw new ConcurrentModificationException();

}

}

final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

}

protected transient int modCount = 0;

}

ArrayList中的remove()的实现

public class ArrayList extends AbstractList implements List,

RandomAccess, Cloneable, java.io.Serializable {

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 remove method that skips bounds checking and does not return

* the value removed.

*/

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; // Let gc do its work

}

}      无论是add()、remove(),还是clear(),只要涉及到修改集合中的元素个数时,都会改变modCount的值

从源码中我们可以看出:

1) Iterator  iterator = list.iterator();执行这语句时,此时Iterator中的expectedModCount = modCount(因为list有6个元素,所有该值为6),

2)遍历到第二个元素即值为5的时候,list.remove(5);从ArrayList中的remove()实现中发现:modCount++;此时modCount的值为7

3)在执行if(iterator.next() == 5)这语句即调用iterator的next()方法时,next()方法实现会调用checkForComodification();,该方法会执行 if (modCount != expectedModCount),即比较modCount和expectedModCount的值是否相等,此时expectedModCount的值为6而modCount的值为7,这两个值不相等,所以抛出

throw new ConcurrentModificationException();这个异常

第三种即解决方案:调用iterator的iterator.remove()方法,该方法的实现中,会执行expectedModCount = modCount;这个语句,即expectedModCount赋值为modCount;

这样就保证expectedModCount 等于modCount,不会抛出ConcurrentModificationException()这个异常

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

public class ListRemove4 {

public static void main(String args[]) {

List list = new ArrayList();

list.add(1);

list.add(5);

list.add(5);

list.add(8);

list.add(5);

list.add(10);

Iterator iterator = list.iterator();

while(iterator.hasNext()){

if(iterator.next() == 5){

iterator.remove();

}

}

outputList(list);

}

private static void outputList(List list) {

for (int i = 0; i < list.size(); i++) {

System.out.print(list.get(i)+" ");

}

}

}运行结果:

1    8    10

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值