(1)、使用foreach進行迭代
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("123");
list.add("345");
list.add("456");
for (String str:list) {
if (str.startsWith("1")){
list.remove(str);
}
}
System.out.println(list);
}
會出現如下異常:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.datahunter.cn.TestModel.TestCoolection.main(TestCoolection.java:20)
為什么會造成該異常:源碼分析
在ArraysList中的Itr內部類中 會使用迭代器去迭代而以上代碼編譯后的結果為:
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String str = (String)var2.next();
if (str.startsWith("1")) {
list.remove(str); // 調用list中remove方法
}
}
會執行next方法做驗證。
public E next() {
checkForComodification(); //對modCount和expectedModCount驗證
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[offset + (lastRet = i)];
}
當使用 list.remove(str)方法時,並沒有對於modCount和expectedModCount進行同步操作則會出現異常情況
(2)、使用for循環遍歷元素時並不會出現異常,移除元素
for (int i=0;i<list.size();i++){
if (list.get(i).startsWith("1")){
list.remove(i);
}
}
System.out.println(list);
}
為什么不會出現異常
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
return oldValue;
}
(3)、使用迭代器遍歷元素,移除元素
迭代器會執行Itr內部類
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
if (iterator.next().startsWith("1")){
iterator.remove();
}
}
System.out.println(list);
執行Itr內部類中的remove方法();
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); //驗證modCount與expectedModCount
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; //會將modCount和expectedModCount進行同步
//modCount 指的是list每一次操作的統計數值
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
List 中的remove源碼
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
return oldValue;
}
System.arraycopy()效果如下圖