今天看來一下Java中list集合部分的八股,發現了一個以前沒注意過的問題,記錄一下
list可以一邊遍歷一邊修改元素嗎?
答:在 Java 中,List在遍歷過程中是否可以修改元素取決于遍歷方式和具體的List實現類。
①:對于普通for循環,只要索引不超過list范圍,可以一邊遍歷一遍修改
②:對于foreach循環,如果想邊遍歷邊修改則必須使用迭代器的remove或set方法實現,否則會拋出異常。解釋如下:
首先,需要知道的是,foreach循環是基于迭代器實現的,而在迭代器中有這樣一個機制,即“快速失敗” (Fail-Fast)機制
快速失敗 (Fail-Fast) 機制
這里就提到了一個新的東西叫modCount,這里簡單介紹一下:
modCount
(Modification Count):
代碼示例
import java.util.ArrayList;
import java.util.List;public class FailFastExample {public static void main(String[] args) {// 1. 創建一個ArrayList并添加元素List<String> names = new ArrayList<>();names.add("Alice");names.add("Bob");names.add("Charlie");// 2. 使用foreach循環遍歷 (底層使用迭代器)for (String name : names) { // Iterator<String> it = names.iterator();while(it.hasNext()) ...System.out.println(name);// 3. 在迭代過程中,嘗試通過集合本身的remove方法刪除元素 (錯誤的做法!)if (name.equals("Bob")) {names.remove("Bob"); // 結構性修改! modCount++!}}}
}
對于這段代碼的解釋:
關鍵總結
modCount
?是集合的“修改計數器”。?結構性修改會遞增它。- 迭代器創建時“拍照”記錄?
expectedModCount
。?它期望在迭代過程中,集合的?modCount
?不應該改變(除非是迭代器自己的?remove()
?方法,該方法會同步更新?expectedModCount
)。 next()
(和?hasNext()
)檢查一致性。?每次調用?next()
?時,都會檢查?modCount == expectedModCount
。- 外部修改導致計數不一致。?如果在迭代過程中,通過集合自身的方法(如?
list.add/remove
,?map.put/remove
)而非迭代器的?remove()
?方法對集合進行了結構性修改,modCount
?就會改變,而迭代器的?expectedModCount
?不變。 - 檢測到不一致立即拋出?
ConcurrentModificationException
。?這就是“快速失敗”的表現。 foreach
?循環依賴迭代器。?因此?foreach
?循環天生就帶有這種快速失敗的特性。- 避免異常:?如果需要在迭代中刪除元素,必須使用迭代器自身的?
remove()
?方法。這個方法在刪除元素后,會同步更新?expectedModCount
?為新的?modCount
,從而保持一致性。