在閱讀阿里巴巴規約的時候發現有一條規約是關於List的【不要在foreach裏面進行元素的remove/add操作,remove請使用Iterator方式】。然後想起以前自己做項目的時候刪除某一元素的邏輯報下標越界錯誤,那時候記得處理是用一新的List進行存儲,然後整體從原List移除所有符合規則的元素,現在做一總結。用這個Iterator主要可以避免下標越界或者遍歷是漏掉符合規則的下一個數據。
先拉出來正確刪除元素的姿勢。正確姿勢是利用Iterator的remove方法。具體操作如下:
public static void main(String[] args) {
List<Integer> lists = new ArrayList<Integer>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
Iterator<Integer> iterator = lists.iterator();
while (iterator.hasNext()){
Integer obj = iterator.next();
if(3==obj || 4==obj){
iterator.remove();
}
}
System.out.println(lists);
}
附上自己比較笨的操作方式:
public static void main(String[] args){
List<Integer> lists = new ArrayList<Integer>();
List<Integer> listscopy = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
int size = lists.size();
for (int i = 0; i < lists.size(); i++) {
if(3==lists.get(i) || 4 == lists.get(i)){
listscopy.add(lists.get(i));
}
}
lists.removeAll(listscopy);
System.out.println(lists);
}
然後常用的錯誤方式有以下三種:
第一種方式,多出現下標越界問題。這個主要原因是因爲我們在循環遍歷時,將我們的長度進行定值確定。而忽略掉在滿足條件時,list的長度是減少的。
public static void main(String[] args) {
List<Integer> lists = new ArrayList<Integer>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
int size = lists.size(); // 定長設置,會造成元素下標越界,如果將for中變量直接換成lists.size()可以嗎?
for (int i = 0; i < size; i++) {
if(3==lists.get(i) || 4 == lists.get(i)){
lists.remove(i); //lists.remove(lists.get(i));
}
}
System.out.println(lists);
}
第二種方式也就是上面的註釋所說,既然會出現下標越界,那我就利用動態的大小不就可以了,但是利用這種方法會產生另外一種情況,就是會忽略掉remove元素後面的一個元素,這個是因爲刪除符合規則的元素後,list長度減一,而同時後面的元素往前補一位,造成當前i值下對應兩個元素。
public static void main(String[] args) {
List<Integer> lists = new ArrayList<Integer>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
int size = lists.size();
for (int i = 0; i < lists.size(); i++) {
if(3==lists.get(i) || 4 == lists.get(i)){
lists.remove(i); //lists.remove(lists.get(i));
}
}
System.out.println(lists); // 打印[1, 2, 4, 5] 此時會將4忽略掉
}
第三種方式是利用增強FOR循環造成的。這種方式會直接給報錯:
ERRORInfo:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
public static void main(String[] args) {
List<Integer> lists = new ArrayList<Integer>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
for (Integer i : lists){
if(3==i || 4==i){
lists.remove(i);
}
}
System.out.println(lists);
}
這種情況下。主要是集合遍歷是使用Iterator, Iterator是工作在一個獨立的線程中,並且擁有一個互斥鎖。Iterator 被創建之後會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往後移動的時候就找不到要迭代的對象,所以按照 fail-fast原則 Iterator 會馬上拋出java.util.ConcurrentModificationException 異常。所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。
【 文章有查詢:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/9347357。】