为什么在for each 循环里 remove 会报错

import java.util.ArrayList;
import java.util.List;

//如下代码
public class Test {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("abc");
		list.add("123");
		list.add("一二三");
		System.out.println(list);
		for(String str : list){
			//运行到下面的这行代码,会报异常。
			list.remove(str);
		}
		System.out.println(list);
	}
}

console输出如下:

[abc, 123, 一二三]
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
 at java.util.AbstractList$Itr.next(AbstractList.java:420)
 at Test.main(Test.java:12)


而使用下面这样的代码就不会报错:

import java.util.ArrayList;
import java.util.List;


public class Test1 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("abc");
		list.add("123");
		list.add("一二三");
		System.out.println(list);
		for (int i = 0; i < list.size(); i++) {
			list.remove(i);
		}
		System.out.println(list);
	}
}

console输出如下:

[abc, 123, 一二三]
[123]

这是为什么呢?

首先,我们要知道,List其实是依靠数组来实现的(至少ArrayLst是的),我们可以看到jdk中ArrayList的源码如下:

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient E[] elementData;

 

然后,要理解这个现象,我们还需要知道for each 是java5 开始加入的语法糖,

for(String str : list)

像这样的语法,最终还是会转成

for (Iterator iterator = list.iterator(); iterator.hasNext();)

执行,那么Test.java中的代码最终还是会转成如下这样的代码执行:

	for (Iterator iterator = list.iterator(); iterator.hasNext();) {
		String string = (String) iterator.next();
		list.remove(string);
	}

最后,如下java的一些bulabulabula官方说明:

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.(concurrent是同时发生,大概意思是当一个object被同时修改的时候,而且该修改是不允许的,就会报这个异常)

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it(一个线程在修改容器,而另外一个线程在遍历这个容器,这样是不允许的). In general, the results of the iteration are undefined under these circumstances. (这样做的会发生不确定的结果)Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. (有一些容器的迭代器检测到这样的行为,就会抛出这个异常)Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.(这种称作fail-fast迭代器,它们失效的很快而且很干净利落而不是愿意冒发生不确定行为的危险, 大概就是说, 遇到这种情况迭代器自己直接就把自己给失效了)

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. (这种异常不总是在一个object被不同线程同时修改时抛出, 即不是总是抛出这个异常)If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.(当一个线程对一个容器操作的时候, 例如用fail-fast迭代器边遍历边修改这个容器,就是抛出这个异常)

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throwConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

我自己的话:

  就是因为

1.用Iterator遍历集合

2.用List对象自己的方法去remove

这两个行为都是对List的实现对象的数组成员进行操作的,两个线程同时访问这个数组,这样有风险,Java不让这么干。

 

 

 

语法糖(syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达-Peter J. Landin发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

这里一定要谢谢军参。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值