1. 程式人生 > 實用技巧 >迭代器遍歷集合時刪除集合中的元素問題

迭代器遍歷集合時刪除集合中的元素問題

使用迭代器Iterator遍歷集合元素時,如果刪除的元素不是倒數第二個資料,則會丟擲ConcurrentModificationException異常

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");list.add("b");list.add("c");
        for (Iterator<String> it = list.iterator();it.hasNext();){
            String first 
= it.next(); if ("a".equals(first)) { list.remove(first); } System.out.println(first); } }

以上程式碼執行結果如下圖:

原因:由於迭代器只負責對各種集合所包含的元素進行迭代,它自己並沒有保留集合元素。它判斷是否還有下一個元素的標準很簡單:如果下一步即將訪問的元素的索引不等於集合的大小,就會返回true,否則,返回false。當程式使用迭代器遍歷集合的倒數第2個元素時,下一步即將訪問的元素的索引為size()-1。如果此時通過List刪除集合的任意一個元素,將導致集合size()變成size()-1,這將導致hasNext()方法返回false,也就是說遍歷會提前結束,永遠訪問不到最後一個元素。迭代器在獲取下一個元素的next()方法中,會呼叫checkForComodification()方法來檢查集合是否被修改:遍歷之前使用expectedModCount保留該集合被修改的次數,每次獲取集合的下一個元素之前,檢查集合的當前修改次數modCount與遍歷之前的修改次數expectedModCount是否相等,如果不相等就直接丟擲ConcurrentModification異常。原始碼如下

hasNext()原始碼:

public boolean hasNext() {
       return cursor != size;
}

next()方法原始碼:

      public E next() {
            // 檢查是否已修改
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData 
= ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } // 如果修改了,直接拋異常 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }