这是一篇纯新手贴,欢迎拍砖。今天一个同事小王跑来问我为什么像下面程序一这样写就不会抛异常。
List<String> list = new ArrayList<String>();
list.add("1");
for(int i=0; i<list.size(); i++)
{
list.remove(0);
}
然而向下面程序二这样写就会抛 java.util.ConcurrentModificationException 异常。
List<String> list = new ArrayList<String>();
list.add("1");
for(String str : list ){
list.remove(0);
}
当时我进入List的源代码跟他解答了一下:
1,List中有一个 modCount 参数。
/**
* 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;
2,当你remove的时候 modCount 的值会改变。modCount++;
(事实证明你add的时候modCount的值也会改变。)
3,for(String str : list) 用到了iterator() 方法。在 iterator.next() 操作中会调用 checkForComodification();
4,checkForComodification 的时候 会判断 modCount != expectedModCount
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
所以,由于你在for(String str : list)中改变了list的结构(remove,add等都不行),所以就会抛ConcurrentModificationException 异常了。
本以为解答清楚啦。。。。没想到我同事小王又问。。为什么? 为什么iterator() 方法中要判断modCount != expectedModCount。为什么不能在for(String str : list) 中更改list的结构。。。。。。
好吧。上网搜索Iterator的工作机制。。。。。。。Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错误。 Iterator是一个单向不可变,只能顺序读取,不能逆序操作的数据结构,当 Iterator指向的原始数据发生变化时,Iterator就会抛异常。
同事小王又问 为什么? 为什么Iterator是索引表没有同步改变?
那个小王他们叫我吃午饭呢。。。那个实在不行你去 Iteye 上发个帖子问问啥的。。。。。
我先吃饭去啦。。。回来再说哈。。。。。。