2013年10月31日 星期四

ArrayList 移除 element 的問題

    今天查了 ArrayList 用法的時候,發現在 Javaworld 有人發了一篇 arraylist的移除問題,下面是他的 Sample Code
 
   ArrayList<integer> list = new ArrayList<integer>();
   list.add(2);
   list.add(2);
   list.add(3);
   list.add(1);
   list.add(2);
   System.out.println(list);

   for (int i=0; i<list.size(); i++){
      if(list.get(i)<3) {
         list.remove(i);
      }
   }
   System.out.println(list);

     原發問者想要將小於 3 的值全部移掉只剩下 3 這個元素,但是卻印出 [1 , 2],上面的的Sample Code 我有修改過,所以顯示為 [2,3,2] ,因為原程式在判斷條件小於3 的 if 後面多了分號 Orz。
     Anyway, 回到原來的問題,當你刪除一個元素時 size 也會跟著縮小,但是 i 的值卻會遞增,在 for 迴圈最後面加入除錯訊息,就可以知道為何印出 [2, 3, 2]。下面是我在 for 迴圈中加入除錯訊息所印出的資料:
i = 0 : [2, 3, 1, 2] size:4
i = 1 : [2, 3, 1, 2] size:4
i = 2 : [2, 3, 2] size:3

    要解決這個問題有下面三種方式

  1. 透過 Iterator 
  2. 透過 for 迴圈反向檢查,可以在 ConcurrentModificationException for ArrayList 中查到方式。
  3. 透過 CopyOnWriteArrayList

透過 Iterator 方式如下:
        
        Iterator<Integer> Allelement = list.iterator();
        while (Allelement.hasNext()) {
            if (Allelement.next() < 3) {
                Allelement.remove(); // 刪除最後 Iterator 所回傳的值,也就是目前所指到值
            }
        }
透過 for 迴圈反向檢查:
        
       for (int i = list.size() - 1; i >= 0; i--) {
            if(list.get(i) < 3){
                list.remove(i);
            }
        }

透過 CopyOnWriteArrayList:
        CopyOnWriteArrayList <Integer> list = 
                     new CopyOnWriteArrayList <Integer>();
        list.add(2);
        list.add(2);
        list.add(3);
        list.add(1);
        list.add(2);
        for (Integer val : list) {
            if (val  < 3) {
                list.remove(val);
            }
        }
請注意,使用 foreach 去詢訪 ArrayList 時,你不可以在 foreach 中 執行 remove,如果執行了應該會出現 java.util.ConcurrentModificationException 的例外訊息。


沒有留言: