增強for為什麼不能刪除集合裡的元素
1.先看看ArrayList物件呼叫iterator()返回的Iterator物件
public Iterator iterator() {
return new Itr();
}
123
2.再看看ArrayList中實現Iterator的內部類Itr
private class Itr implements Iterator {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
…
}
12345
cursor表示下一個返回元素的下標,可以理解成 遊標;lastRet表示上一次返回的元素下標。另ArrayList有個size屬性,表示ArrayList中的元素個數。
3.看迭代器的hasNext()方法
public boolean hasNext() {
return cursor != size;
}
123
hasNext() 的判斷條件是cursor != size. 只要沒遍歷到最後一個元素,就返回true.
4.下面是next()
public E next() {
…
int i = cursor; // cursor為當前需要返回元素的下標
…
cursor = i + 1; // cursor向後移動一個位置,指向下一個要返回的元素
return (E) elementData[lastRet = i]; // 對lastRet賦值,然後返回當前元素
}
1234567
5.現在看下例子
ArrayList list = new ArrayList();
list.add(“e1”);
list.add(“e2”);
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String str = (String)var2.next();
if(“e1”.equals(str)) {
list.remove(“e1”);
}
}
12345678910
執行會報錯,這種操作是不被允許的。
6.解釋:
第一次 呼叫var2.hasNext(),此時滿足條件 cursor(0) != size(2),然後執行 var2.next(),此時 cursor=1
執行 list.remove(“e1”),此時,list的size將從2變為1當執行完第一次迴圈,進入第二次hasNext()判斷時,cursor=1而且size=1,導致Iterator認為已經遍歷結束,因此e2將被漏掉。此時,過程已非常清楚。list本有2個元素,Iterator第一次獲取元素時,程式刪掉了當前元素,導致list的size變為1。Iterator第二次獲取元素時,開心說到:”list一共只有一個元素,我已經遍歷了一個,easy,輕鬆搞定!”。
矛盾點在於:hasNext() 是根據已fetch元素和被遍歷物件的size動態判斷的,一旦遍歷過程中被遍歷物件的size變化,就會出現以上問題。
7.正確的姿勢,在使用迭代器遍歷的時候對集合元素進行增刪
將remove操作交給Iterator來處理,使用Iterator介面提供的remove操作。
List list = new ArrayList<>();
list.add(“e1”);
list.add(“e2”);
for (Iterator iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if (“e1”.equals(str)) {
iterator.remove();
}
if ("e2".equals(str)) {
System.out.println("element 2 fetched");
}
}
1234567891011121314
執行結果:element 2 fetched 被正常列印出來。 那Iterator的remove()又是怎麼做的?下面是ArrayList中迭代器的remove方法。
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet); // 呼叫ArrayList的remove移除元素,且size減1
cursor = lastRet; // 將遊標回退一位
lastRet = -1; // 重置lastRet
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
1234567891011121314
因為Iterator.remove()在執行集合本身的remove後,同時對遊標進行了 “校準”。
相關文章
- list增強for迴圈刪除元素報錯
- 阿里巴巴為什麼這樣強制從List中刪除元素阿里
- J2SE-刪除List集合元素
- 網路負面訊息如何刪除?為什麼不能直接刪除客戶投訴的負面資訊?
- JS刪除陣列裡的某個元素方法JS陣列
- MongoDB 資料庫建立刪除、表(集合)建立刪除、資料增刪改查MongoDB資料庫
- jQuery為元素新增和刪除classjQuery
- win10開始裡的文件不能刪除怎麼辦 win10開始裡的文件無法刪除如何處理Win10
- 集合框架-增強for框架
- 【Java】增強for迴圈,三種迭代的能否刪除Java
- 建立元素和刪除元素
- jQuery刪除元素jQuery
- jQuery 刪除元素jQuery
- 我們為什麼會刪除不了叢集的 Namespace?namespace
- 什麼是資料增強?
- HashMap 之元素刪除HashMap
- removeChild()刪除li元素REM
- JavaScript 刪除指定的li元素JavaScript
- 為什麼不能往Android的Application物件裡儲存資料AndroidAPP物件
- jquery為指定的元素新增或者刪除指定樣式類jQuery
- 為什麼我的Jbuilder7現在不能除錯Jsp了?UI除錯JS
- MongoDB 集合的插入、更新、刪除操作MongoDB
- 在skinUtil.java中為什麼不直接刪除cookie!JavaCookie
- 區塊鏈世界裡不能信什麼?區塊鏈
- u盤裡的檔案無法刪除 如何刪除u盤裡刪不掉的檔案
- 為什麼在mc檔案裡面定義的FEATURE不能用(轉)
- 字典,元組,集合的增刪改查
- JavaScript刪除陣列元素JavaScript陣列
- JavaScript 建立和刪除元素JavaScript
- jQuery刪除指定子元素jQuery
- jQuery刪除指定li元素jQuery
- c++ map刪除元素C++
- c++ vector刪除元素C++
- Java ArrayList刪除特定元素的方法Java
- 為什麼 MySQL 裡的 ibdata1 檔案不斷的增長?MySql
- [譯] 一文教你什麼是漸進增強,為什麼它很重要?
- 蘋果Feedback是什麼?有什麼用?怎麼刪除?蘋果
- jQuery實現的為元素新增或者刪除class樣式類jQuery