foreach刪除元素爲什麼會報錯?

2020-06-23

foreach刪除元素爲什麼會報錯

Math.max() 返回兩個數中大的那個,源碼裏是一個三元運算符
final:	
	final修飾的類不能被繼承。(Sting就是一個被final修飾的類,我們只能用,不用繼承)
	final修飾的變量,是一個常量,只能賦值一次。
protected:
	可以被子類,同package下類使用,不對外公開的訪問修飾符 在非static修飾下,子類不能通過new父類對象直接調用
default(不寫修飾符) 在一個包下的能訪問
transient : 
	瞬態 “不可序列化狀態”。
	密碼,銀行卡號等敏感信息,爲了安全起見,不希望在網絡操作(主要涉及到序列化操作,本地序列化緩存也適用)中被傳輸。這些信息對應的變量就可以被定義爲transient類型。換句話說,這個字段的生命週期僅存於調用者的內存中。
   List<Integer> arrayList = new ArrayList<Integer>();
		arrayList.add(1);
		arrayList.add(2);
		arrayList.add(3);
		arrayList.add(4);
		System.out.println(arrayList);
		for (Integer ele : arrayList) {
			if (ele == 2) {arrayList.remove(ele);}
		}
	// java.util.ConcurrentModificationException 
	// at java.util.AbstractList$Itr.checkForComodification(Unknown Source)

開始分析:
	在編譯的時候編譯器會自動將對for這個關鍵字的使用轉化爲對目標的迭代器的使用
    for(Iterator<Integer> iterator = list.iterator(); iterator.hasNext(); 沒有i++){
        Integer ele = iterator.next();
        if(ele == 2) 
            list.remove(ele);
    }

modCount:修改次數,被定義在ArrayList的父類AbstractList中 protected transient int modCount = 0
步驟1.add 時,先判斷是否需要擴容,無論是否需要,modCount 都會++
	三次add,modCount = 3, size=3;
步驟2:對Iterator進行初始化。返回一個Itr()類的一個實例(Itr是ArrayList的一個成員內部類)
	int cursor;       // cursor:表示下一個要訪問的元素的索引, 當前爲 0
	int expectedModCount = modCount;	// 3
步驟3:循環條件的判斷
	public boolean hasNext() {
	    return cursor != size();	// 相等時就已經到底了
	}
步驟4:循環體內的.next
	final void checkForComodification() {
	    if (modCount != expectedModCount)
	        throw new ConcurrentModificationException();
	}	
	public E next() {
	    checkForComodification();	// 此時 modCount=expectedModCount=3
	    int i = cursor;
	    ...
	   	...
	   	...
	    cursor = i + 1;	// 1
	    ...
	}
步驟5:進行.remove操作
	public boolean remove(Object o) {
	   if (o == null) {
		...
	       fastRemove(index);
	      	...
	           }
	   } else {
	      ...
	      fastRemove(index);
	      ...
	           }
	   }
	   ...
}
	private void fastRemove(int index) {
	    modCount++;	// 4
     	System.arraycopy(elementData, index+1, elementData, index, numMoved);// 調用System.arraycopy方法實現刪除元素 size = 2;
	}
步驟6:remove完成後,開始下一次循環,執行 .next 判斷
	此時:modCount == 4; 而expectedModCount == 3; 
	拋 java.util.ConcurrentModificationException 

特殊情況:
	若是在倒數第二個元素進行刪除操作時,經過前面的遍歷,next()方法將cursor增加至2,只比size=31。
	在remove()操作時,size-1=2hasNext()發現cursor=size,程序並沒有遍歷最後一個元素,程序正常終止。
	如果要修改其他位置元素,都會拋異常

正確姿勢:
	List<String> list = new ArrayList<>();
	list.add("e1");
	list.add("e2");
	
	for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
	    String str = iterator.next();
	    if ("e1".equals(str)) {
	        iterator.remove();	// 將remove操作交給Iterator來處理(是的,只用改變這一步)
	    }
	}
迭代器的remove方法與集合的remove方法,最大的不同是,迭代器的remove方法中包括對遊標和expectedModCount的修正。

如果是多線程情況: 
	在使用iterator迭代的時候使用synchronized或者Lock進行同步;
	使用併發容器CopyOnWriteArrayList代替ArrayList和Vector。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章