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<Integer> list = new ArrayList<Integer>();
	        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<Integer> 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<Integer> list = new ArrayList<Integer>();
	        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<Integer>  iterator = list.iterator();
	        while(iterator.hasNext()){
	        	if(iterator.next() == 5){
	        		list.remove(5);
	        	}
	        }

	        outputList(list);
	    }

	    private static void outputList(List<Integer> list) {
	        for (int i = 0; i < list.size(); i++) {
	            System.out.print(list.get(i)+"    ");
	        }
	    }

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


  

   之所以报上面的错误是因为发生了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<E> extends AbstractCollection<E> implements List<E> {


	    public Iterator<E> iterator() {
		return new Itr();
	    }

	    private class Itr implements Iterator<E> {
		/**
		 * 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<E> extends AbstractList<E> implements List<E>,
			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<Integer>  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<Integer> list = new ArrayList<Integer>();
	        list.add(1);
	        list.add(5);
	        list.add(5);
	        list.add(8);
	        list.add(5);
	        list.add(10);

	        Iterator<Integer>  iterator = list.iterator();
	        while(iterator.hasNext()){
	        	if(iterator.next() == 5){
	        		iterator.remove();
	        	}
	        }

	        outputList(list);
	    }

	    private static void outputList(List<Integer> list) {
	        for (int i = 0; i < list.size(); i++) {
	            System.out.print(list.get(i)+"    ");
	        }
	    }


}
运行结果:

     1    8    10 

       

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值