繁体   English   中英

Java:如何在迭代/添加元素时从列表中删除元素

[英]Java: How to remove elements from a list while iterating over/adding to it

这个问题是在描述(和解决)问题的一个比较特殊的情况下这个问题

我有两个方法,stopAndRemove(ServerObject服务器)和close()方法。 后者应关闭所有服务器并将其从服务器列表中删除。 该列表定义为

List<ServerObject> server. 

我不想在closeCurrentlyOpen中使用stopAndRemove中的几乎相同的代码,所以我想做类似的事情:

public void closeCurrentlyOpen() {
   for(ServerObject server : this.servers) {
       stopAndRemove(server)
   }
}

这将不起作用,因为这将导致ConcurrentModificationException。 我试着复制一份清单

List<ServerObject> copyList = new ArrayList<ServerObject>(this.servers);

并将其用作foreach循环的列表。 但是当我在copyList上迭代时,另一个线程可能会将服务器附加到服务器列表,但closeCurrentlyOpen应该会产生一个emtpy列表。 当addServerToList方法同步到servers-list时,执行此操作

public void closeCurrentlyOpen() {
   synchronized(this.servers) {
     for(ServerObject server : this.servers) {
        stopAndRemove(server)
     }
    }
}

将通过修改解决问题。 但是我不能在stopAndRemove方法中同步代码,如果直接调用它是必需的。

在我看来,这三种方法的设计可能需要修改。 任何人的想法?

从stopAndRemove()拆分方法stop()。 然后使用显式迭代器编写循环,执行stop,然后使用iterator.remove()。

方法名称中的“和”是代码气味。

也许这是错误的方法,但我总是创建一个删除集合,其中包含对需要删除的对象的索引或引用。 然后我遍历该集合并从原始集合中删除这些索引/对象。 可能不是最有效的,但它完成了工作。

代替

for(Collection things : thing)  
    things.remove(thing)

我用

Collection toRemove = new LinkedList();
for(things : thing)
    toRemove.add(thing);

for(toRemove : thing)
    things.remove(thing)

当我之前完成此操作时,我总是使用“旧学校”LinkedList集合,Iterator和Iterator.remove()方法来删除当前项目。

您可能会发现有关ConcurrentModificationException的这篇文章在此领域有一些建议。

将所有ServerObject停止代码从stopAndRemove重构为私有stopServer方法,然后在stopAndRemove和closeCurrentlyOpen中单独执行删除。 然后你可以使用ListIterator来删除它们(或者只是在for循环中将它们全部停止并在结尾处清除列表)。

与firebird84相似。 但你可以使用removeAll(Collection c)api

for(String exitingPermission : existingPermissions){                
    //remove all permissions for the screen and add the new ones
    if(exitingPermission.split("_")[0].equals(screen)){
        removePermissions.add(exitingPermission);
    }
 }
existingPermissions.removeAll(removePermissions);

你应该得到一个迭代器并使用它删除。 您将获得异常,因为迭代器在java中是快速失败的

回答问题的标题,而不是给定示例的具体细节。 事实上,这种解决方案在特定情况下甚至不合适(重构是合适的,正如其他人所建议的那样)。

但是,似乎很多java程序员都不知道CopyOnWriteArrayList (JDK自1.5以来的一部分),并且正在尝试将自己的解决方案推向同一个问题(迭代前的复制列表)。

...从目录列表中删除非XML文件...

List<File> files = Arrays.asList(dir.listFiles());

Iterator<File> i = files.iterator();

while (i.hasNext()) {
    File file = i.next();
    if (!file.getName().endsWith(".xml")) {
        i.remove();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM