我知道,
时,施法不是正确的词java.lang.Object
-> java.util.concurrent.CopyOnWriteArrayList<E>
和
java.lang.Object
-> java.util.AbstractCollection<E>
-> java.util.AbstractList<E>
-> java.util.ArrayList<E>
但我想要的是将CopyOnWriteArrayList
的行为添加到ArrayList
。
例如:
我想做以下。但是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的类型更改为另一个是最大的解决方案。
答案 0 :(得分:4)
使用增强型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();
}
}
澄清编辑,因为您显然不熟悉迭代器及其功能。来自the Oracle tutorial on Collections:
Iterator
是一个允许您遍历a的对象 如果,有选择地收集和从集合中删除元素 期望。您可以通过调用Iterator
来获取集合的iterator()
方法请注意,
Iterator.remove()
是唯一可以安全修改的方法 迭代期间的集合;如果是,则行为未指定 在迭代时,底层集合以任何其他方式进行修改 正在进行中。在需要时使用
Iterator
代替for-each
构造:
- 删除当前元素。
for-each
构造隐藏了迭代器,因此您无法调用remove()
。因此,for-each
构造不可用于过滤。
答案 1 :(得分: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();
答案 2 :(得分:2)
您可以使用迭代器的remove
方法来实现此目的:
Iterator<TestCls> i = tstArry.iterator();
while (i.hasNext()) {
TestCls value = i.next();
if (value.getVal1().equals("a1"))
i.remove();
}
但是,应该注意的是,这与具有不同用例的CopyOnWriteArrayList
大致正交。