2013-01-08 36 views
1

这是一个跟进我刚才的问题:只有一条线爪哇 - Collection.remove()具有不同的行为在不同条件下

Collection - Iterator.remove() vs Collection.remove()

下面的代码,这显然是不同的两片,但有一个抛出异常,其他抛出异常。你能解释一下这个区别吗?

List<String> list = new ArrayList<String> 
(Arrays.asList("noob1","noob2","noob3")); 


System.out.println(list); 

for (String str : list) { 
    if (str.equals("noob2")) { 
     list.remove(str); 
    } 
} 

运行正常,但如果我改变的条件

if (!str.equals("noob2")) 

代码抛出异常!

+4

什么异常? –

+1

java.util.ConcurrentModificationException – NINCOMPOOP

+0

但它如何取决于“if”条件? – NINCOMPOOP

回答

4

在这种情况下会发生什么,您将删除第二个列表元素。

List<String> list = new ArrayList<String> 
     (Arrays.asList("noob1", "noob2", "noob3", "noob4")); 

System.out.println(list); 

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
    String str = iterator.next(); 
    if (str.equals("noob3")) { 
     System.out.println("Checking "+str); 
     list.remove(str); 
    } 
} 
System.out.println(list); 

打印

[noob1, noob2, noob3, noob4] 
Checking noob1 
Checking noob2 
Checking noob3 
[noob1, noob2, noob4] 

通过去除将大小已经减少到您已遍历元件的数量的第二最后一个元素。

// from ArrayList.Itr 
    public boolean hasNext() { 
     return cursor != size; 
    } 

这导致环前next()进行并发modifcation检查提前退出。如果你删除任何其他元素next()被调用,你会得到一个CME。

BTW一些​​东西,也绕过检查

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
    String str = iterator.next(); 
    System.out.println("Checking "+str); 
    if (str.equals("noob2")) { 
     list.remove("noob1"); 
     list.remove("noob3"); 
    } 
} 

只要集合的大小是一样的,因为它是到指数,不进行检查。

1

for循环只是列表的迭代器扫描的简化语法。如果列表在其下被修改,迭代器可能会引发异常,但不能保证。由于hasNext,迭代器通常会提前处理一个元素,使得第一种情况不太可能受到列表修改的影响。到“noob2”被删除的时候,迭代器已经知道“noob3”了。

1

我想这个例外是因为你试图改变你正在循环的集合而不是因为if条件。

我建议您创建一个新的列表只包含验证条件的项目。将它们添加到新列表中,并避免更改原始集合。

1

实际上,在“随意”迭代过程中,您绝对不应该删除集合的元素。如果必须在某个循环中修改集合,则必须使用iterator来执行这些操作。

public class Test { 
     public static void main(String... args) { 
      List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3")); 

      System.out.println(list); 

      for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { 
       String str = iterator.next(); 
       if (!str.equals("noob2")) { 
        iterator.remove(); 
       } 
      } 
      System.out.println(list); 
     } 
    } 
1

这是因为您试图从Collection中删除您目前正在迭代。做一个小小的改变,你可以做你想做的事:

String[] strValues = {"noob1","noob2","noob3"}; // <<< Array 
List<String> list = new ArrayList<String>(Arrays.asList(strValues)); 

System.out.println(list); 

for (String str : strValues) { // << List is duplicate of array so can iterate through array 
    if (!str.equals("noob2")) { 
     list.remove(str); 
    } 
} 

这应该工作。希望

0

嗯,你的第一个情况,因为迭代器的索引2,你在索引中移除元素Iterator.hasNext()返回false不会抛出异常1.

Iterator<String> itr = list.iterator(); 
    while(itr.hasNext()){ 
     String s= itr.next(); 
     if(s.equals("noob2")){ 
      list.remove(s); // size of the list is 2 here 
      System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration) 
     } 
    } 

你可以测试它清楚地使用一个简单的for循环:

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

输出:

[noob1, noob2, noob3] 
noob2 
3 
2 

通知吨他删除元素后列表的大小,增加后失败。 这是假的