Java中迴圈刪除List中元素
Java中迴圈刪除List中元素
寫在開頭:最近在處理一個包裝類時候,把Mapper查詢到的資料暫存到了ArrayList中,後續做迴圈遍歷刪除操作的時候,當時採用了foreach迴圈,結果彈出了ConcurrentModificationException錯誤。於是乎就在部落格上找解決方案,最後整理總結一下。
遍歷方式:
for、foreach、iterator
常規需求:
刪除一個、多個元素
準備工作:User實體類、初始化UserList
// 初始化列表 List<User> list = User.getUserList(); // 遍歷列表元素 showAll(list);
結果:
展示當前列表資料
User{name='name0', age=0, address='address0'}
User{name='name1', age=1, address='address1'}
User{name='name2', age=2, address='address2'}
User{name='name3', age=3, address='address3'}
User{name='name4', age=4, address='address4'}
for
-
刪除單個元素:
// for for (int i = 0; i< list.size(); i++) { if (list.get(i).getAge() == 2) { list.remove(list.get(i)); } } showAll(list);
結果:正常
User{name='name0', age=0, address='address0'} User{name='name1', age=1, address='address1'} User{name='name3', age=3, address='address3'} User{name='name4', age=4, address='address4'}
-
刪除多個元素:
變更控制條件:list.get(i).getAge() > 2
結果:age=3的元素被刪除,為何age=4的元素未被刪除呢?
User{name='name0', age=0, address='address0'} User{name='name1', age=1, address='address1'} User{name='name2', age=2, address='address2'} User{name='name4', age=4, address='address4'}
-
總結:
List列表在刪除某個元素之後,list.size()發生了變化,除此之外,元素的索引index也在發生變化,所以當刪除某個元素之後,根據元素索引繼續進行遍歷,這樣就很有可能會漏掉某些元素。因此,list.remove()方式建議刪除特定元素,不建議用於刪除多個元素。 -
補充說明:特定元素,具有唯一性的元素,亦或者判定條件具有唯一性
比如:我們將列表資料的age屬性全部置為2,即:
User{name='name0', age=2, address='address0'} User{name='name1', age=2, address='address1'} User{name='name2', age=2, address='address2'} User{name='name3', age=2, address='address3'} User{name='name4', age=2, address='address4'}
我們再進行刪除單個元素的操作會發現結果:
User{name='name1', age=2, address='address1'} User{name='name3', age=2, address='address3'}
驗證了我們上述總結,我們簡單敘述下遍歷流程:當對元素刪除之後,後續元素將整體向前移動覆蓋(copy)
第一次:user:i = 0 -> name0 -> 符合條件 -> remove -> size=4 , i++ User{name='name1', age=2, address='address1'} User{name='name2', age=2, address='address2'} User{name='name3', age=2, address='address3'} User{name='name4', age=2, address='address4'} 第二次:user:i = 1 -> name2 -> 符合條件 -> remove -> size=3 , i++ User{name='name1', age=2, address='address1'} User{name='name3', age=2, address='address3'} User{name='name4', age=2, address='address4'} 第三次:user:i = 2 -> name4 -> 符合條件 -> remove -> size=2 , i++ User{name='name1', age=2, address='address1'} User{name='name3', age=2, address='address3'} 第四次:user:i = 3 -> i > list.size -> 跳出迴圈
foreach
-
刪除單個元素**(刪除多個元素同for)**
// foreach for (User user : list) { if (user.getAge() == 2) { list.remove(user); } } showAll(list);
結果:java.util.ConcurrentModificationException 異常
User{name='name0', age=0, address='address0'}
User{name='name1', age=1, address='address1'}
User{name='name2', age=2, address='address2'}
User{name='name3', age=3, address='address3'}
User{name='name4', age=4, address='address4'}
分析:
刪除元素後繼續迴圈會報錯誤資訊ConcurrentModificationException,因為元素在使用的時候發生了併發的修改,丟擲異常。
併發修改:list.remove() + 索引推進
解決方案:新增break,強制跳出迴圈遍歷
// foreach
for (User user : list) {
if (user.getAge() == 2) {
list.remove(user);
break;
}
}
showAll(list);
結果:可以正常刪除
User{name='name0', age=0, address='address0'}
User{name='name1', age=1, address='address1'}
User{name='name3', age=3, address='address3'}
User{name='name4', age=4, address='address4'}
iterator
迭代器遍歷方式:建議使用
刪除單個、多個元素:
// iterator
Iterator<User> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next().getAge() > 2) {
iterator.remove();
}
}
showAll(list);
結果:
User{name='name0', age=0, address='address0'}
User{name='name1', age=1, address='address1'}
User{name='name2', age=2, address='address2'}
補充說明:
採用迭代器方式進行遍歷,可以正常迴圈以及單個、多個元素刪除,需要特別注意:remove方法要使用iterator,而不是list的remove方法。
迭代器(Iterator)
迭代器是一種設計模式,它是一個物件,它可以遍歷並選擇序列中的物件。迭代器通常被稱為“輕量級”物件。
Java中的Iterator功能比較簡單,並且只能單向移動:
-
使用方法iterator()要求容器返回一個Iterator。第一次呼叫Iterator的next()方法時,它返回序列的第一個元素。
注意:iterator()方法是java.lang.Iterable介面,被Collection繼承。
-
使用next()獲得序列中的下一個元素。
-
使用hasNext()檢查序列中是否還有元素。
-
使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現,為List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。