ArrayList刪除元素後長度變小了,元素的索引也會跟着改變,可是迭代的下標沒有跟着相應的改變。java
import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Created with IDEA by penelopeWu * Date:2017/9/22 9:18 */ public class SafeOptrationOfArrayList { public static void main(String[] args) { List<String> list = new ArrayList(); /* list.add("c"); list.add("a"); list.add("c"); list.add("b"); list.add("c"); list.add("d"); list.add("c"); */ list.add("a"); list.add("c"); list.add("c"); list.add("b"); list.add("c"); list.add("c"); list.add("d"); list.add("c"); } /** * 刪除Arraylist中值爲"c"的元素 * 不安全 * @param list */ public static void removeListElement1(List<String> list) { for (int i = 0; i < list.size(); i++) { if ("c".equals(list.get(i))) { list.remove(i); } } } /** * 刪除Arraylist中值爲"c"的元素 * 安全 * @param list */ public static void removeListElement2(List<String> list) { for (int i = 0; i < list.size(); i++) { if ("c".equals(list.get(i))) { list.remove(i); --i;//刪除元素的同時,要讓迭代下標也跟着改變 } } } /** * 刪除Arraylist中值爲"c"的元素 * 安全 * @param list */ public static void removeListElement3(List<String> list) { Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String str = iterator.next(); if ("c".equals(str)){ iterator.remove(); //爲何iterator的remove方法是可靠的? } } } }
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; //須要移動的元素個數 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //數組複製,被刪除元素以後的元素各前移一位 elementData[--size] = null; // clear to let GC do its work // 空出的位置 設置爲null。 return oldValue; //返回被刪除的元素 }
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
先看下ArrayList的內部類Itr的源碼編程
/** * An optimized version of AbstractList.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; //敲黑板!!,將ArrayList的modCount賦值給Itr的expectedModCount,expectedModCount接下來有大用處 public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); //首先檢查ArrayList是否被結構性修改 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();//首先檢查ArrayList是否被結構性修改 try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { //敲黑板!!若是ArrayList被結構性修改,這時modCount和expectedModCount就再也不一致了,直接拋異常 if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }