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

2022-09-02 23:26:36

这个问题是这个问题中描述的(和解决的)问题的一个更特殊的案例。

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

List<ServerObject> server. 

我不想在 closeCurrentLyOpen 中从 stopAndRemove 获得几乎相同的代码,所以我想做这样的事情:

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

这不起作用,因为这将导致并发模式异常。我试图复制列表

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

并将其用作前循环的列表。但是,当我迭代copyList时,其他线程可能会将服务器附加到服务器列表中,但closeCurrentlyOpen应该导致emtpy列表。当 addServerToList 方法同步到服务器列表时,请执行此操作

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

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

在我看来,这三种方法的设计可能需要一个修井。有人有想法吗?


答案 1

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

方法名称中的“and”是代码异味。


答案 2

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

而不是

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

我使用

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

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