Java 对于每个,使用迭代器vs For i

Java 对于每个,使用迭代器vs For i,java,Java,如果forEach获得ConcurrentModificationException,为什么人们建议使用Iterator?在我的情况下,解决此异常的最佳方法是使用fori而不是foreach。 那么我有权利吗?如果我错了,请向我解释 例如: 例外 private void init() { addToCollection("Dog"); addToCollection("Cat"); showCollection(stringArrayLis

如果forEach获得
ConcurrentModificationException
,为什么人们建议使用
Iterator
?在我的情况下,解决此异常的最佳方法是使用fori而不是foreach。
那么我有权利吗?如果我错了,请向我解释

例如:

例外

   private void init() {
        addToCollection("Dog");
        addToCollection("Cat");
        showCollection(stringArrayList);
    }

    private void showCollection(List<String> collection) {

        for (String s : collection) {
            if (s.equals("Dog")){
                collection.remove(s);
            }
        }

    }

    private void addToCollection(String value) {
        stringArrayList.add(value);
    }
}
private void init(){
添加到集合(“狗”);
添加到集合(“Cat”);
showCollection(stringArrayList);
}
私有void showCollection(列表集合){
用于(字符串s:集合){
如果(s.等于(“狗”)){
收集。移除;
}
}
}
私有void addToCollection(字符串值){
stringArrayList.add(值);
}
}
没有:

private void init() {
    addToCollection("Dog");
    addToCollection("Cat");
    showCollection(stringArrayList);
}

private void showCollection(List<String> collection) {

    for (int i = 0; i < collection.size(); i++) {
        if (collection.get(i).equals("Dog")){
            collection.remove(i);
        }
    }

}

private void addToCollection(String value) {
    stringArrayList.add(value);
}
private void init(){
添加到集合(“狗”);
添加到集合(“Cat”);
showCollection(stringArrayList);
}
私有void showCollection(列表集合){
对于(int i=0;i
用于i

在索引的帮助下进行迭代时,不会得到
ConcurrentModificationException
,因为这种情况下无法检测到。但发生的情况是,每次删除对象时,循环都会跳过一个对象,因为删除时索引会调整,但
i
不会。如果在移除对象后减少
i
,它将按预期工作

for (int i = 0; i < collection.size(); i++) {
    if (collection.get(i).equals("Dog")){
        collection.remove(i);
        i--;
    }
}
对于i

在索引的帮助下进行迭代时,不会得到
ConcurrentModificationException
,因为这种情况下无法检测到。但发生的情况是,每次删除对象时,循环都会跳过一个对象,因为删除时索引会调整,但
i
不会。如果在移除对象后减少
i
,它将按预期工作

for (int i = 0; i < collection.size(); i++) {
    if (collection.get(i).equals("Dog")){
        collection.remove(i);
        i--;
    }
}
开发时有一条“规则”:永远不要修改正在循环的内容。如果在
集合中循环,则不应在循环中修改它!如果要在循环中修改集合,请找到一种通过其他内容(如集合的副本或迭代器)进行循环的方法

遵守此规则的原因是为了避免错误。您可以创建一些黑客/技巧,以允许您修改正在循环的列表。但是强迫你不这样做,避免你错过你的黑客和创建一个错误的时间


在您的情况下,当您为每个循环执行一次测试时,系统能够看到您不遵守上述规则。所以它给你带来了一个例外

当您使用索引执行for循环时。系统无法检测到您修改了循环中的集合。但您仍然会遇到问题,因为您将删除集合中的项,但不会相应地修改索引,因此会跳过一些值。在这里,您可以编写一个“hack”,每次删除项目时都修改索引,但我强烈建议不要这样做。为了遵守上述规则,如果使用索引进行循环,请不要在循环中修改它

唯一好的方法是使用迭代器。此对象旨在允许在循环期间进行修改

开发时有一条“规则”:永远不要修改正在循环的内容。如果在
集合中循环,则不应在循环中修改它!如果要在循环中修改集合,请找到一种通过其他内容(如集合的副本或迭代器)进行循环的方法

遵守此规则的原因是为了避免错误。您可以创建一些黑客/技巧,以允许您修改正在循环的列表。但是强迫你不这样做,避免你错过你的黑客和创建一个错误的时间


在您的情况下,当您为每个循环执行一次测试时,系统能够看到您不遵守上述规则。所以它给你带来了一个例外

当您使用索引执行for循环时。系统无法检测到您修改了循环中的集合。但您仍然会遇到问题,因为您将删除集合中的项,但不会相应地修改索引,因此会跳过一些值。在这里,您可以编写一个“hack”,每次删除项目时都修改索引,但我强烈建议不要这样做。为了遵守上述规则,如果使用索引进行循环,请不要在循环中修改它

唯一好的方法是使用迭代器。此对象旨在允许在循环期间进行修改

按照这个例子。此处已中断,因为您调用下一个迭代器的次数太多

对ForEach

for (Suit suit : suits)
    for (Rank rank : ranks)
        sortedDeck.add(new Card(suit, rank));
这里不会被打破。并为ForEach添加一个点

如您所见,for-each构造与 仿制药。它保留了所有类型的安全性,同时移除了 剩余的杂乱。因为不必声明迭代器,所以 不必为它提供通用声明

作为个人意见。这取决于何时使用for和foreach。一切都是相对的。但是当这个bug发生时,ForEach为您节省了大量调试时间

如果要修改循环内的集合,请使用
CopyOnWriteArrayList

ArrayList的一种线程安全变体,其中包含所有变异操作 (添加、设置等)通过创建 底层数组

这通常成本太高,但可能比 当遍历操作的数量远远超过突变时的替代方案,以及 当您还不能或不想同步遍历时,此选项非常有用 需要排除并发线程之间的干扰

按照这个例子。此处已中断,因为您调用下一个迭代器的次数太多

// BROKEN - throws NoSuchElementException!
for (Iterator i = suits.iterator(); i.hasNext(); )
    for (Iterator j = ranks.iterator(); j.hasNext(); )
        sortedDeck.add(new Card(i.next(), j.next()));
for (Suit suit : suits)
    for (Rank rank : ranks)
        sortedDeck.add(new Card(suit, rank));