foreach删除元素为什么会报错?

2020-06-23

foreach删除元素为什么会报错

Math.max() 返回两个数中大的那个,源码里是一个三元运算符
final:	
	final修饰的类不能被继承。(Sting就是一个被final修饰的类,我们只能用,不用继承)
	final修饰的变量,是一个常量,只能赋值一次。
protected:
	可以被子类,同package下类使用,不对外公开的访问修饰符 在非static修饰下,子类不能通过new父类对象直接调用
default(不写修饰符) 在一个包下的能访问
transient : 
	瞬态 “不可序列化状态”。
	密码,银行卡号等敏感信息,为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输。这些信息对应的变量就可以被定义为transient类型。换句话说,这个字段的生命周期仅存于调用者的内存中。
   List<Integer> arrayList = new ArrayList<Integer>();
		arrayList.add(1);
		arrayList.add(2);
		arrayList.add(3);
		arrayList.add(4);
		System.out.println(arrayList);
		for (Integer ele : arrayList) {
			if (ele == 2) {arrayList.remove(ele);}
		}
	// java.util.ConcurrentModificationException 
	// at java.util.AbstractList$Itr.checkForComodification(Unknown Source)

开始分析:
	在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用
    for(Iterator<Integer> iterator = list.iterator(); iterator.hasNext(); 没有i++){
        Integer ele = iterator.next();
        if(ele == 2) 
            list.remove(ele);
    }

modCount:修改次数,被定义在ArrayList的父类AbstractList中 protected transient int modCount = 0
步骤1.add 时,先判断是否需要扩容,无论是否需要,modCount 都会++
	三次add,modCount = 3, size=3;
步骤2:对Iterator进行初始化。返回一个Itr()类的一个实例(Itr是ArrayList的一个成员内部类)
	int cursor;       // cursor:表示下一个要访问的元素的索引, 当前为 0
	int expectedModCount = modCount;	// 3
步骤3:循环条件的判断
	public boolean hasNext() {
	    return cursor != size();	// 相等时就已经到底了
	}
步骤4:循环体内的.next
	final void checkForComodification() {
	    if (modCount != expectedModCount)
	        throw new ConcurrentModificationException();
	}	
	public E next() {
	    checkForComodification();	// 此时 modCount=expectedModCount=3
	    int i = cursor;
	    ...
	   	...
	   	...
	    cursor = i + 1;	// 1
	    ...
	}
步骤5:进行.remove操作
	public boolean remove(Object o) {
	   if (o == null) {
		...
	       fastRemove(index);
	      	...
	           }
	   } else {
	      ...
	      fastRemove(index);
	      ...
	           }
	   }
	   ...
}
	private void fastRemove(int index) {
	    modCount++;	// 4
     	System.arraycopy(elementData, index+1, elementData, index, numMoved);// 调用System.arraycopy方法实现删除元素 size = 2;
	}
步骤6:remove完成后,开始下一次循环,执行 .next 判断
	此时:modCount == 4; 而expectedModCount == 3; 
	抛 java.util.ConcurrentModificationException 

特殊情况:
	若是在倒数第二个元素进行删除操作时,经过前面的遍历,next()方法将cursor增加至2,只比size=31。
	在remove()操作时,size-1=2hasNext()发现cursor=size,程序并没有遍历最后一个元素,程序正常终止。
	如果要修改其他位置元素,都会抛异常

正确姿势:
	List<String> list = new ArrayList<>();
	list.add("e1");
	list.add("e2");
	
	for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
	    String str = iterator.next();
	    if ("e1".equals(str)) {
	        iterator.remove();	// 将remove操作交给Iterator来处理(是的,只用改变这一步)
	    }
	}
迭代器的remove方法与集合的remove方法,最大的不同是,迭代器的remove方法中包括对游标和expectedModCount的修正。

如果是多线程情况: 
	在使用iterator迭代的时候使用synchronized或者Lock进行同步;
	使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值