这个问题是this question中描述(和解决)问题的一个更特殊的例子。
我有两个方法,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方法中的代码,如果直接调用它是必需的。
在我看来,这三种方法的设计可能需要修改。 任何人的想法?
答案 0 :(得分:17)
从stopAndRemove()中分离出一个方法stop()。然后使用显式迭代器编写循环,执行stop,然后使用iterator.remove()。
方法名称中的“和”是代码气味。
答案 1 :(得分:14)
这可能是错误的方法,但我总是创建一个删除集合,其中包含对需要删除的对象的索引或引用。然后我遍历该集合并从原始集合中删除这些索引/对象。可能不是最有效的,但它完成了工作。
而不是
for(Collection things : thing)
things.remove(thing)
我用
Collection toRemove = new LinkedList();
for(things : thing)
toRemove.add(thing);
for(toRemove : thing)
things.remove(thing)
答案 2 :(得分:4)
当我之前完成此操作时,我总是使用“旧学校”LinkedList集合,Iterator和Iterator.remove()方法来删除当前项目。
答案 3 :(得分:3)
您可能会发现this article about ConcurrentModificationException在这方面有一些建议。
答案 4 :(得分:2)
将所有ServerObject停止代码从stopAndRemove重构为私有stopServer方法,然后在stopAndRemove和closeCurrentlyOpen中单独执行删除操作。然后你可以使用ListIterator来删除它们(或者只是在for循环中将它们全部停止并在结尾处清除列表)。
答案 5 :(得分:1)
你应该得到一个迭代器并使用它删除。您将获得异常,因为迭代器在java中是fail-fast。
答案 6 :(得分:1)
回答问题的标题,而不是给定示例的具体细节。事实上,这种解决方案在特定情况下甚至不合适(重构是合适的,正如其他人所建议的那样)。
然而,似乎很多java程序员都不知道CopyOnWriteArrayList(JDK自1.5以来的一部分),并且正在尝试将自己的解决方案推向同一个问题(迭代前的副本列表)。
答案 7 :(得分:1)
...从目录列表中删除非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();
}
}
答案 8 :(得分:1)
与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);