4

我知道,铸造不是正确的词

java.lang.Object
  -> java.util.concurrent.CopyOnWriteArrayList<E>

java.lang.Object 
  -> java.util.AbstractCollection<E>
      -> java.util.AbstractList<E>
          -> java.util.ArrayList<E>

但我想要的是CopyOnWriteArrayListArrayList.

例如:
我想做以下事情。但是 tstArry 是一个ArrayList. 不是CopyOnWriteArrayList

for(TestCls testCls : tstArry)
    if(testCls.getVal1().equals("a1"))
        tstArry.remove(testCls);

或者这是完成工作的唯一方法?

for(int i = 0; i < tstArry.size(); i++)
    if(tstArry.get(i).getVal1().equals("a1"))
        tstArry.remove(i--);

tstArry 是一个来自我没有控制权的类的 ArrayList。因此,请将 ArrayList 的类型更改为另一种是最有效的解决方案。

4

3 回答 3

5

remove()使用增强for-each循环时,您不能从迭代集合中。for-each循环Iterator<TestCls>隐式使用。JavaDoc明确指出

此类的iterator()listIterator() 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时候列表在结构上被修改,除了通过迭代器自己的remove()add()方法之外的任何方式,迭代器将抛出一个 ConcurrentModificationException.

循环在for-each内部创建一个迭代器并使用它来遍历列表。然后你改变列表的结构......迭代器必须失败。问题是您无权访问迭代器方法,因此您必须Iterator<TestCls>显式使用。生成的遍历字节码将是相同的,唯一的区别是您可以在遍历列表时从列表中删除元素。

for (Iterator<TestCls> iter = tstArry.iterator(); iter.hasNext(); ) {
    TextCls testCls = iter.next();
    if(testCls.getVal1().equals("a1")) {
        iter.remove();
    }
}

澄清 EDIT 因为您显然不熟悉迭代器及其功能。来自关于集合的 Oracle 教程

AnIterator是一个对象,它使您能够遍历集合并在需要时有选择地从集合中删除元素。你可以通过调用它的 方法来获得Iterator一个集合。iterator()

请注意,这Iterator.remove()是在迭代期间修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则行为未指定。

当您需要时使用Iterator而不是构造:for-each

  • 删除当前元素。该for-each构造隐藏了迭代器,因此您不能调用remove(). 因此,该for-each 构造不可用于过滤。
于 2013-06-21T08:48:44.133 回答
4

关键是Effective Java,第 39 条:在需要时制作防御性副本

拿你从其他班级得到的清单。复制一份:

List<TestCls> myCopy = new ArrayList<>(theOtherList);

然后从您的副本中删除不需要的元素,而不是从原始集合中删除。为此,您需要使用 Iterator.remove() 方法。

或者您使用像Guava这样的库,它可以让您使用谓词过滤集合:

Predicate<TestCls> predicate = new Predicate<TestCls>(){
   public boolean apply(TestCls data){
       // add check here
   }
};
List<TestCls> myList = 
    FluentIterable.from(theOtherList).filter(predicate).toList();
于 2013-06-21T09:54:30.240 回答
2

您可以使用迭代器的remove方法来实现这一点:

Iterator<TestCls> i = tstArry.iterator();

while (i.hasNext()) {
    TestCls value = i.next();
    if (value.getVal1().equals("a1"))
        i.remove();
}

但是,应该注意的是,这在很大程度上与CopyOnWriteArrayList具有不同用例的情况正交。

于 2013-06-21T08:49:13.190 回答