一个ArrayList在循环过程中删除,会不会出问题,为什么?
ArrayList中的remove方法(注意ArrayList中的remove有两个同名方法,只是入参不同,这里看的是入参为Object的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++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }
执行System.arraycopy方法,导致删除元素时涉及到数组元素的移动。
删除方法1:
public static void remove(ArrayList<String> list) { for (int i = 0; i < list.size(); i++) { String s = list.get(i); if (s.equals("bb")) { list.remove(s); } } }
遍历第二个元素字符串bb时因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动(也是字符串bb)至当前位置,导致下一次循环遍历时后一个字符串bb并没有遍历到,所以无法删除。
倒序遍历时即使发生元素删除也不影响后序元素遍历。
删除方法2:
public static void remove(ArrayList<String> list) { for (String s : list) { if (s.equals("bb")) { list.remove(s); } } }
modCount+1,涉及到iterator迭代。
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }
调用checkForComodification()方法
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
使用迭代器就会避免这种情况:
Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.equals("bb")) { it.remove(); } }