下图是来自阿里巴巴java开发手册,里面的例子有些特殊,在后面会有一般的例子,请往后看。
个人理解:在foreach循环里面进行元素的remove/add操作就是:在foreach循环里使用集合本身的remove/add方法, Iterator方式就是使用集合对应的iterator的remove/add方法,即下图中的iterator.remove() //删除当前遍历的这个元素
foreach本质上是java中的语法糖,对数组操作时,底层原理和普通的for循环一样;而对列表操作时,实际上是采用了迭代器的方法。
为什么不要使用集合本身的remove/add方法呢?
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); for (String temp : list) { if("1".equals(temp)){ list.remove(temp); } }
反编译结果如下:
List list = new ArrayList(); list.add("1"); list.add("2"); Iterator i$ = list.iterator(); // 语句1 do { if(!i$.hasNext()) break; String temp = (String)i$.next(); // 语句2
if("1".equals(temp)) list.remove(temp); // 语句3
} while(true);
ArrayList的iterator()方法如下:
重要参数:
modCount:是ArrayList修改的次数,在add()、remove()/removeAll()、clear()等方法中会修改modCount的值。
expectedModCount:在获得ArrayList对象的Iterator的时候,把modCount的初值赋给expectedModCount
语句1: list.iterator() 返回的是一个Itr对象,
语句2: next()方法中,首先会执行checkForComodification()方法(源码如下),如果 modCount != expectedModCount 就会抛出ConcurrentModificationException异常,在语句3中,执行了list.remove(temp),会修改modCout的值,那么在下一次执行next()方法的时候就会报错!! 所以不要在foreach循环里面进行元素的remove/add操作
另:如果把上面代码 if("1".equals(temp)) 改成 if("2".equals(temp)) 即直接删除最后一个元素,会抛出ConcurrentModificationException异常,因为在删除最后一个元素的过程中,首先cursor 等于 size, 然后执行 a.remove(temp) 【-》modCount发生改变】方法后,size=size-1, 再执行hashNext()方法,发现返回结果是false(cursor != size) 又会进行一次循环,在next()方法里面就抛出异常。 所以不要在foreach循环里面进行元素的remove/add操作
public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
为什么说上面的例子有些特殊,因为list集合中只有两个数据,如果是只删除第一个数据,执行list.remove(temp)后, cursor=size-1, size=size-1, 所以就会推出循环。没有抛出异常。
将例子改为:
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String temp : list) { if("1".equals(temp)){ list.remove(temp); } }
现在有了三个元素,除开直接删除倒数第二个元素不会抛出异常(因为会出现 cursor=size-1, size=size-1的情况,然后退出循环),直接删除其他元素都会抛出ConcurrentModificationException异常!!
如果是下面的写法,更是会抛出异常!
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String temp : list) { list.remove(temp); }
直接使用iterator的remove/add方法对集合做修改:
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); Iterator iterator = list.iterator(); while(iterator.hasNext()) { String temp = (String) iterator.next(); iterator.remove(); }