Iterator for Java Framework Collection的不同结果 [英] Different results with Iterator for Java Framework Collection

查看:77
本文介绍了Iterator for Java Framework Collection的不同结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对主要Java Framework Collection类(不仅是List类)上Iterator的不同行为有一些疑问.

I have some questions about the different behaviors of Iterator on the main Java Framework Collection classes (not only for the List class).

  1. 列表

如果我写for-each,我将有一个例外:

If I write for-each I will have an exception:

Collection<String> cc= new ArrayList<>(3);
        cc.add("Cio");
        cc.add("Mio");
        cc.add("Tio");
for (String s:cc) {
    System.out.println(s);
    cc.remove(s);            //Exception
}

如果我使用Iterator,我将没有例外:

If I use the Iterator, I will have not an exception:

for (Iterator<String> it =cc.iterator(); it.hasNext();) {
    String s =it.next();
    if (s.startsWith("C"))
        it.remove();
}

  1. ArrayDeque

这与ArrayDeque不同,实际上,如果我使用for-each,我会 也不例外:

This is different for ArrayDeque, infact if I use for-each, I will have not an exception:

ArrayDeque<String> greetings = new ArrayDeque<String>();
        greetings.push("hello");
        greetings.push("hi");
        greetings.push("ola");
        greetings.pop(); 
        greetings.peek();
        while (greetings.peek() != null)
        System.out.print(greetings.pop());

但是,如果我使用迭代器,我将有一个例外:

But if I use the iterator, I will have an exception:

Iterator<String> it = greetings.iterator();
        while(it.hasNext()) {
            System.out.println(greetings.pop()); //Exception
        }

为什么?迭代器是否会引发其他JFC集合的异常,尤其是:HashSet,TreeSet,LinkedList?

Why? And does the iterator throw an exception for the other JFC collections, in particular: HashSet, TreeSet, LinkedList?

非常感谢!

A.

推荐答案

ArrayList

列表维护一个modCount字段,每次对列表进行结构修改时该字段都会增加.

The list maintains a modCount field that is incremented each time a structural modification is done to the list.

结构修改是指可以更改列表大小的修改, 或以迭代的方式干扰它 可能会产生错误的结果.

Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.

进一步...

如果此字段的值意外更改,则迭代器(或列表) 迭代器)将抛出ConcurrentModificationException,以响应 下一个,删除,上一个,设置或添加操作.这提供了 快速失败的行为,而不是面对不确定的行为 迭代期间的并发修改. 子类是可选的.

If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.Use of this field by subclasses is optional.

如果子类希望提供快速失败的迭代器(和列表) 迭代器),则只需在其add(int, E)和remove(int)方法(以及它覆盖的任何其他方法) 从而对列表进行结构上的修改.

If a subclass wishes to provide fail-fast iterators (and list iterators), then it merely has to increment this field in its add(int, E) and remove(int) methods (and any other methods that it overrides that result in a structural modification the list.

列表迭代代码的两个方面:

The two peice of list iteration code :

1.

for (String s:str1) {
    System.out.println(s);
    str1.remove(s);  
}

2.

Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
    i1.next();
    i1.remove();
}

-看起来可能相同,但内部有些不同.

--may seem identically but are internally a bit different.

值得一提的是,列表的迭代器具有expectedModCount.在迭代时修改列表时,应该与modCount同步.

Its worth mentioning that the iterator of the list maitains a expectedModCount. That should be in sync with modCount when modifying the list while iterating.

在第二种情况下,在第一种情况下,String s:str1获取迭代器,检查hasNext()并调用next().区别在于remove()方法调用. str1.remove(s);调用ArrayList的remove方法.这会增加modCount而不是expectedModCount.因此,在第二次迭代中,当调用next()时,它将引发ConcurrentModificationException.另一方面,在第二种情况下,i1.remove();从ArrayList中的Iterator实现中调用remove方法.这会增加modCountexpectedModCount以及- Bingo .

In 1st case, String s:str1 gets the iterator, checks hasNext() and calls the next(), just like in the 2nd case. The difference comes in remove() method call. str1.remove(s); calls the remove method of the ArrayList. This increments the modCount but not expectedModCount. So in the second iteration, when next() is called it throws ConcurrentModificationException. On the other hand, in 2nd case, i1.remove(); calls the remove method from Iterator implementation in ArrayList. This increments the the modCount and expectedModCount and -- Bingo.

注意:第二种情况下缺少i1.next();会导致IllegalStateExcepton.这是因为列表中下一个元素的光标未更新.

Note: Missing the i1.next(); in the second scenario will cause IllegalStateExcepton. This is because the cursor for the next element in the list is not updated.

TakeAway::在迭代列表时不要调用list.remove(element)方法.该方法应在不进行迭代时调用.

TakeAway: Dont call the list.remove(element) method while iterating the list. This method is meant to be called when not in an iteration.

ArrayDeque

如果您像这样迭代ArrayDeque:

If you iterate the ArrayDeque like this:

Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
    i1.next();
    i1.remove();
}

-其工作方式与ArrayList完全相同.

-- it works the exact same way as its ArrayList counterpart.

当调用ArrayDeque类的pop()push()方法时,您实际上并没有在队列上进行迭代,只需修改队列的开头或结尾即可.这就像不在迭代中(而不是ArrayList的Iterator的remove())时调用ArrayList类的remove()方法一样.这不符合结构修改的条件.因此它不会引发异常.

When calling pop() or push() method of the ArrayDeque class, you don't actually iterate on the queue, you just modify the head or tail of the queue. This is just like calling remove() method of the ArrayList class when not in Iteration (not the remove() of Iterator of ArrayList). This doesn't qualify to be a structural modification. So it doesn't throw an Exception.

这篇关于Iterator for Java Framework Collection的不同结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆