2011-11-18 143 views
5

我在遍历列表时删除列表元素时遇到问题。代码:动态删除列表中的元素

For (WebElement element: list){ 
    if (!element.isEnabled() || !element.isSelected()){ 
     list.remove(element); 
    } 
} 

我得到ConcurrentModificationException,我完全理解。我在通过列表的循环中删除列表中的项目。直观地说,这会搞砸循环的索引。

我的问题是,我该如何从该列表中删除不是enabledselected的元素?

回答

8

以除去从一个列表中的元素在一个循环中最简单的方法是使用常规iterator.remove()

+0

我不知道它是否一定是最简单的。 'remove()'是'Iterator '接口上的一个可选功能。值得注意的是'remove()'在'Iterator '上,并且仅仅由'ListIterator '继承。 – corsiKa

6

修改列表,同时通过它使用迭代的外迭代,在某种程度上,结果,以使用一个ListIterator和删除元素在未定义的行为。您必须明确使用迭代器:

Iterator<WebElement> iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 

有关更多信息,请参阅this question

+0

嗯,我明白了。因此,如果我想将'Iterator'转换回'List',有没有比在循环中逐个添加每个元素更简单的方法? – jamesfzhang

+2

这不会将'List'转换为'Iterator' - 一个'Iterator'只是一个作用于该列表本身的对象 - 它是一个迭代整个列表的接口。当你调用'iter.remove()'时,它确实在修改底层列表。 – Claudiu

+0

哇,太棒了!谢谢。 – jamesfzhang

0

从以下事实的ConcurrentModificationException结果可知,对于-每个语法只是使用Iterator接口语法糖。

列表迭代器有什么是被称为“快速失败”的属性,这意味着任何改变从迭代器提供的接口列表发不谈,立即失效说迭代器。试图使用失效的迭代器触发你的异常。

@Claudiu已经张贴了这个代码,但为了清楚起见,我就会把它在这里。为了做你想做的事情,你将不得不放弃花哨的语法,并使用一个简单的迭代器。

Iterator<WebElement iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 
3

其他人建议使用列表迭代器。这对我来说已经证明是有用的,但不幸的是它依赖于一种方法remove(),这被Iterable<E>接口认为是可选的。

答曰的Javadoc,永不复还(重点煤矿):

无效删除()

从底层集合的最后一个元素通过 迭代器(可选操作)返回删除。

要解决这个问题已被证明对我来说更有用的是删除列表。

List<E> removed = new ArrayList<E>(); 
for(E element : list) { 
    if(someCondition) removed.add(element); 
} 
list.removeAll(removed); 

这还有一个额外的好处,就是您可以像删除方法一样为您提供删除内容的历史记录。

+0

我非常喜欢这个(+1)。然而,元素E应该有一个适当的覆盖等于方法 – GETah

+1

@GETah不一定。没有它就可以正常工作,甚至可能是首选。你可能会让他们来自一种工厂方法,在这种方法中,你对equals方法的需求少得多,严格依赖于平等的参考。 – corsiKa

+1

哇,我也很喜欢这个!非常好的想法。 – jamesfzhang