java迭代器移除元素出现并发修改异常的原因

6 篇文章 0 订阅

  • 迭代器(Iterator的对象)主要用于遍历集合,体现的就是迭代器模式。
  • Iterator接口定义了以下四种方法。
  1.  boolean hasNext():如果集合还没遍历完就返回true。
  2. Object next():返回集合里的下一个元素。       
  3. void remove():删除集合里上一次next方法返回的元素。
  4. void forEachRemaining(Consumer action):这是java8新增的默认方法,可用Lambda表达式遍历数组。
 使用迭代器遍历元素时不能不能通过Collection接口中的remove方法删除元素,只能用Interator的remove方法删除元素,下面根据案例和源代码分析原因。
public class InteratorTest {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("zhangsan");
		list.add("lisi");
		list.add("wangwu");
		list.add("zhaoliu");
		
		Iterator<String> it = list.iterator();
		while(it.hasNext()) {
			String str = it.next();//java.util.ConcurrentModificationException并发修改异常
			System.out.println(str);
			if("lisi".equals(str)) {
				list.remove(str);
			}
		}
		System.out.println(list);
	}
}
并发修改异常: 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection(来自java API),从这里可以看出迭代器和集合是在不同线程里的。查看资料知道了,迭代器其实在另外一个线程复制了一个一摸一样的集合进行遍历的。当用集合的remove方法删除元素时,迭代器是不会知道的,所以就会抛出异常。下面看源码分析。
   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];
        }
而用迭代器的ramove方法删除元素时,实际在底层还是用的集合的remove方法,所以迭代器和集合修改元素的次数一样是不会出现异常的。源码如下:
 public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);//用的还是集合的remove方法
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
并发修改异常出现的原因已经找到了。但是Arraylist迭代器会出现下面这种情况,当我们用集合删除方法删除倒数第二个元素时,并不会出现异常。
public class InteratorTest {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("zhangsan");
		list.add("lisi");
		list.add("wangwu");
		list.add("zhaoliu");
		
		Iterator<String> it = list.iterator();
		while(it.hasNext()) {
			String str = it.next();//不会出现并发修改异常
			System.out.println(str);
			if("wangwu".equals(str)) {//用集合Remove方法删除倒数第二个元素
				list.remove(str);
			}
		}
		System.out.println(list);
	}
}
原因是这样的,当while循环到第三次的时候也就是遍历到“wangwu”时,这时候迭代器的cursor(游标相当于指针)变量值为2,集合元素个数为4。执行完it.next()方法后cursor值为3,接着删除“wangwu”这个元素后,集合的size变成了3。当继续第四次循环时现判断hasNext()当cursor值和size值相等时返回false,所以不会执行while循环里面的语句,自然不会执行next()方法,所以时不会出现异常的。
public boolean hasNext() {
            return cursor != size;//根据上面的说法在循环第四次是返回的是false,不会执行循环里的的代码
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值