第一種迭代刪除方式:
第二種迭代刪除方式:
第三種迭代刪除:
第四種迭代刪除:
第五種迭代刪除:
第六種:
ArrayList中remove()方法的機制,首先看源碼:
真正的刪除操作在fastRemove(),首先定義一個新列表的長度newSize,其值為原列表長度減一 (newS-ze = size-1),然后將 索引 i 之后的數組元素全部向前進一位(System.arraycopy(es, i + 1, es, i, newSize - i)),接着最后一個原數組的最后一個元素置為null(es[size = newSize] = null;)。
所以使用for循環遍歷刪除的時候,每次循環時都要重新獲取ArrayList的長度,並在刪除元素之后將索引減1(i--)。
或者倒序刪除。
迭代器刪除:
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; // prevent creating a synthetic constructor Itr() {} // 當前迭代指示器是否指向列表末尾 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 { // 調用fastRemove刪除元素 ArrayList.this.remove(lastRet); // 迭代指示器指向被刪除元素所在的索引位置 cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); final int size = ArrayList.this.size; int i = cursor; if (i < size) { final Object[] es = elementData; if (i >= es.length) throw new ConcurrentModificationException(); for (; i < size && modCount == expectedModCount; i++) action.accept(elementAt(es, i)); // update once at end to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
黃色部分是關鍵,刪除元素后迭代指示器重新指向 “新” 元素,確保每一個元素都能被迭代指示器 “指” 過。