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(); } }