1. 程式人生 > >Java中迴圈刪除List中元素

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

  1. 刪除單個元素:

     // 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'}
    
  2. 刪除多個元素:

     變更控制條件: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'}
    
  3. 總結:
    List列表在刪除某個元素之後,list.size()發生了變化,除此之外,元素的索引index也在發生變化,所以當刪除某個元素之後,根據元素索引繼續進行遍歷,這樣就很有可能會漏掉某些元素。因此,list.remove()方式建議刪除特定元素,不建議用於刪除多個元素。

  4. 補充說明:特定元素,具有唯一性的元素,亦或者判定條件具有唯一性

    比如:我們將列表資料的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

  1. 刪除單個元素**(刪除多個元素同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功能比較簡單,並且只能單向移動:

  1. 使用方法iterator()要求容器返回一個Iterator。第一次呼叫Iterator的next()方法時,它返回序列的第一個元素。

     注意:iterator()方法是java.lang.Iterable介面,被Collection繼承。
    
  2. 使用next()獲得序列中的下一個元素。

  3. 使用hasNext()檢查序列中是否還有元素。

  4. 使用remove()將迭代器新返回的元素刪除。

Iterator是Java迭代器最簡單的實現,為List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。