对JAVA集合进行遍历删除时务必要用迭代器

0.情景引出

对新手来说,遍历一个集合时难免会碰到删除操作,直接删除的话,肯定是要抛异常的

 1 public static void main(String[] args) {
 2 
 3         List<String> list = new ArrayList<>();
 4         for(int i=0;i<10;i++){
 5             list.add(String.valueOf(i));
 6         }
 7         System.out.println(list.toString());
 8         System.out.println("----------------------");
 9         for (String str:list){
10             if(str.equals("5"))
11                 list.remove(str);
12         }
13          //会抛出异常java.util.ConcurrentModificationException
14 
15     }

异常的文档说明:

所以呢,聪明的你,大概可以找解决方案了,我以前呢倒是会建一个临时的集合C2和需要删减的集合C1一致,一个循环,一个删减,对于迭代器好像都是敬而远之!!

1.问题解决

咳咳,这里呢,就是为了让自己明白点

 1 public static void main(String[] args) {
 2 
 3         List<String> list = new ArrayList<>();
 4         for(int i=0;i<10;i++){
 5             list.add(String.valueOf(i));
 6         }
 7         System.out.println(list.toString());
 8 
 9         System.out.println("----------------------");
10 
11         Iterator iter = list.iterator();
12         while (iter.hasNext()){
13             String str = (String) iter.next();
14             if(str.equals("5"))
15                 iter.remove();
16                 //错误的写法,list.remove(str);,这种类似于上面的
17         }
18 
19         System.out.println(list);
20 
21     }

文章到此应该结束了。下面只是补充下,我自己对Iterator的理解

2.扩展Iterator

  2.1 我们先来看一下Iterator的api解释:

这个移除元素的特点看来是与生俱来的吧,

2.2 我们再看一下ArrayList中的Iterator实现:

 1 private class Itr implements Iterator<E> {
 2    /**
 3     * Index of element to be returned by subsequent call to next.
 4     */
 5    int cursor = 0;
 6    /**
 7     * Index of element returned by most recent call to next or
 8     * previous.  Reset to -1 if this element is deleted by a call
 9     * to remove.
10     */
11    int lastRet = -1;
12    /**
13     * The modCount value that the iterator believes that the backing
14     * List should have.  If this expectation is violated, the iterator
15     * has detected concurrent modification.
16     */
17    int expectedModCount = modCount;
18    public boolean hasNext() {
19            return cursor != size();
20    }
21    public E next() {
22            checkForComodification();
23        try {
24        E next = get(cursor);
25        lastRet = cursor++;
26        return next;
27        } catch (IndexOutOfBoundsException e) {
28        checkForComodification();
29        throw new NoSuchElementException();
30        }
31    }
32    public void remove() {
33        if (lastRet == -1)
34        throw new IllegalStateException();
35            checkForComodification();
36        try {
37        AbstractList.this.remove(lastRet);
38        if (lastRet < cursor)
39            cursor--;
40        lastRet = -1;
41        expectedModCount = modCount;
42        } catch (IndexOutOfBoundsException e) {
43        throw new ConcurrentModificationException();
44        }
45    }
46    final void checkForComodification() {
47        if (modCount != expectedModCount)
48        throw new ConcurrentModificationException();
49    }
50    }

Iterator采用cursor来来维护自已的状态,而上ArrayList采用size属性来维护自已的状态

当size出现变化时,cursor并不一定能够得到同步,除非这种变化是Iterator主动导致的。

从上面的代码可以看到当Iterator.remove方法导致ArrayList列表发生变化时,他会更新cursor来同步这一变化。但其他方式导致的ArrayList变化,Iterator是无法感知的。ArrayList自然也不会主动通知Iterator们,那将是一个繁重的工作。Iterator到底还是做了努力:为了防止状态不一致可能引发的无法设想的后果,Iterator会经常做checkForComodification检查,以防有变。如果有变,则以异常抛出,所以就出现了上面的异常。

 

posted @ 2017-06-02 17:25  谢幕ゾ华丽  阅读(1173)  评论(0编辑  收藏  举报