。遍历集合找到特定的元素并将其删除,两种实现: private void testDelete() { 当通过list.remove(str)删除时报异常:java.util.ConcurrentModificationException。而通过it.remove()删除时一切正常。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方法: 这里用的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异常。 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(); } 到这里问题就很明白了! 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>>) 网上其他解释: 文中指出:“有意思的是如果你的 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./topic/145383 同意这种解释,从代码出发,比较好理解。 |
|