我有一个我想迭代的ArrayList.迭代它时,我必须同时删除元素.显然这会抛出一个java.util.ConcurrentModificationException.
处理此问题的最佳做法是什么?我应该先克隆列表吗?
我删除不在循环本身但是代码的另一部分的元素.
我的代码看起来像这样:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
Run Code Online (Sandbox Code Playgroud)
a.doSomething可能打电话Test.removeA();
Jon*_*eet 289
两种选择:
originalList.removeAll(valuesToRemove)在结尾处调用 remove()在迭代器本身上使用该方法.请注意,这意味着您无法使用增强型for循环.作为第二个选项的示例,从列表中删除长度大于5的任何字符串:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
Run Code Online (Sandbox Code Playgroud)
Var*_*har 16
来自ArrayList的JavaDocs
此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException.
suh*_*n07 10
您试图从高级"for循环"中的列表中删除值,这是不可能的,即使您应用任何技巧(您在代码中执行).更好的方法是将迭代器级别编码为其他建议.
我想知道人们怎么没有建议传统的for循环方法.
for( int i = 0; i < lStringList.size(); i++ )
{
String lValue = lStringList.get( i );
if(lValue.equals("_Not_Required"))
{
lStringList.remove(lValue);
i--;
}
}
Run Code Online (Sandbox Code Playgroud)
这也有效.
小智 10
在Java 8中,您可以使用Collection Interface并通过调用removeIf方法执行此操作:
yourList.removeIf((A a) -> a.value == 2);
Run Code Online (Sandbox Code Playgroud)
更多信息可以在这里找到
小智 8
你应该以传统的方式迭代数组
每次从列表中删除元素时,后面的元素都将向前推进.只要您不更改迭代之外的元素,以下代码就可以工作.
public class Test(){
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff(){
for(int i = (abc.size() - 1); i >= 0; i--)
abc.get(i).doSomething();
}
public void removeA(A a){
abc.remove(a);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
以正常方式执行循环,这java.util.ConcurrentModificationException是与访问的元素相关的错误.
所以尝试:
for(int i = 0; i < list.size(); i++){
lista.get(i).action();
}
Run Code Online (Sandbox Code Playgroud)
小智 6
在迭代列表时,如果要删除元素是可能的。让我们看下面的例子,
ArrayList<String> names = new ArrayList<String>();
names.add("abc");
names.add("def");
names.add("ghi");
names.add("xyz");
Run Code Online (Sandbox Code Playgroud)
我有以上名称的数组列表。我想从上面的列表中删除“ def”名称,
for(String name : names){
if(name.equals("def")){
names.remove("def");
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码引发ConcurrentModificationException异常,因为您在迭代时正在修改列表。
因此,要通过这种方式从Arraylist中删除“ def”名称,
Iterator<String> itr = names.iterator();
while(itr.hasNext()){
String name = itr.next();
if(name.equals("def")){
itr.remove();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码,通过迭代器,我们可以从Arraylist中删除“ def”名称,然后尝试打印该数组,您将看到以下输出。
输出:[abc,ghi,xyz]
一种选择是将removeA方法修改为-
public void removeA(A a,Iterator<A> iterator) {
iterator.remove(a);
}
Run Code Online (Sandbox Code Playgroud)
但这意味着你doSomething()应该能够传递iterator给remove方法.不是一个好主意.
你能用两步法做到这一点:在迭代列表的第一个循环中,不是删除所选元素,而是将它们标记为要删除.为此,您可以简单地将这些元素(浅拷贝)复制到另一个元素中List.
然后,一旦完成迭代,只需removeAll从第一个列表中执行第二个列表中的所有元素.
这是一个示例,我使用不同的列表添加要删除的对象,然后我使用stream.foreach从原始列表中删除元素:
private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
long diff;
long diffSeconds;
List<Object> objectsToRemove = new ArrayList<>();
for(CustomerTableEntry item: customersTableViewItems) {
diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
diffSeconds = diff / 1000 % 60;
if(diffSeconds > 10) {
// Element has been idle for too long, meaning no communication, hence remove it
System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
objectsToRemove.add(item);
}
}
objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}
Run Code Online (Sandbox Code Playgroud)
小智 5
有时老派是最好的。只需进行一个简单的 for 循环,但确保从列表末尾开始,否则当您删除项目时,您将与索引不同步。
List<String> list = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
if ("removeMe".equals(list.get(i))) {
list.remove(i);
}
}
Run Code Online (Sandbox Code Playgroud)