遍历集合找到特定的元素并将其删除,两种实现:
private void testDelete() { List < String > list = new ArrayList < String > (); for ( int i = 0 ; i < 10 ; i ++ ) { String str = " ck0 " + i; list.add(str); } for (Iterator it = list.iterator(); it.hasNext();) { String str = (String) it.next(); if (str.equals( " ck05 " )) { // list.remove(str); // 第一种删除方法 it.remove(); // 第二种删除方法 } } }当通过list.remove(str)删除时报异常:java.util.ConcurrentModificationException。而通过it.remove()删除时一切正常。
先看看List中的remove方法:
这里用的ArrayList,ArrayList中remove方法源代码:
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 void fastRemove( int index) { modCount ++ ; // 特别注意这里,这里只增加了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 }到这里似乎还没有找到抛出异常的地方,接着看。删除后得到下一个元素的代码,it.next(): it为AbstractList的内部类Iterator的一个实例。
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor ++ ; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }也就是集合被修改的次数(modCount)和它的期望值(expectedModCount)不同,那么就会抛出ConcurrentModificationException异常。 再来看看Iterator的remove()方法的源代码:
public void remove() { if (lastRet == - 1 ) throw new IllegalStateException(); checkForComodification(); try { AbstractList. this .remove(lastRet); if (lastRet < cursor) cursor -- ; lastRet = - 1 ; expectedModCount = modCount; // 设置expectedModCount } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }到这里问题就很明白了! 在我们foreach时也会出现这种情况,但是在用普通的for循环却不会。
for (String str : list){ if (str.equals( " ck05 " )){ list.remove(str); // 报异常 } } for ( int i = 0 ; i < list.size(); i ++ ){ String str = list.get(i); if (str.equals( " ck05 " )){ list.remove(str); // 正常 } }“之所以可以这样做(用foreach遍历集合),是因为Java SE5引入了新的的被称为Iterable的接口,该接口保护了一个能够产生Iterator的iterator()方法,并且Iterable接口被 foreach用来在序列中移动。”(<<Thinking in java>>)
网上其他解释:
http://www.javaeye.com/topic/124788
文中指出:“有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候, ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.” 测试了下,当只要一个元素时仍然会报异常!
http://www.javaeye.com/topic/145383 同意这种解释,从代码出发,比较好理解。
http://gceclub.sun.com.cn/yuanchuang/week-14/iterator.html
嗯,是否有还使用foreach的解决方案?