[英]How to safely remove other elements from a Collection while iterating through the Collection
[英]While iterating over a collection of event handlers, how do you safely remove a handler from *within* a callback?
我对某事感到有些困惑。 Java的文档告诉我们在使用Iterator对象迭代该集合时从集合中删除项目时没有定义的行为,唯一安全的方法是使用Iterator.remove()。
那么,如果在迭代列表的过程中,其中一个处理程序决定将它自己作为监听器删除的话,你会如何安全地从ArrayList中删除一个事件处理程序?
// in public class Dispatcher
public void dispatchEvent(){
Iterator<IEventHandler> iterator = mHandlers.iterator();
IEventHandler handler = null;
while(iterator.hasNext()){
handler = iterator.next();
handler.onCallbackEvent();
}
}
public void insertHandler(IEventHandler h){
mHandlers.add(h);
}
public void removeHandler(IEventHandler h){
mHandlers.remove(h);
}
同时,处理程序像这样被实例化......
final Dispatcher d = new Dispatcher();
d.insertHandler(new IEventHandler(){
@Override
public void onCallbackEvent(){
Log.i(" callback happened ");
d.removeHandler(this);
}
});
看到潜在的问题? 您正在使用Iterator进行迭代时 ,由于在该特定处理程序中声明的onCallbackEvent() 而从ArrayList中删除处理程序。
这是一个棘手的问题吗? 处理这种情况的安全方法是什么?
这是实现事件系统时非常常见的问题。 唯一的解决方案是在更改时复制处理程序列表。 您可以在insertHandler / removeHandler方法中自己执行此操作,或者只使用CopyOnWriteArrayList。
您可以重新实现removeHandler
来存储计划删除的处理程序。
public void removeHandler(IEventHandler h){
mHandlersToRemove.add(h);
}
然后在进行任何调度之前将其删除。
public void dispatchEvent(){
mHandlers.removeAll(mHandlersToRemove);
mHandlersToRemove.clear();
...
您也可以删除在年底dispatchEvent
,但你只能从处理程序中移除。 (否则您可能会分派给已删除的处理程序。)
如果您对此问题的理论解决方案感兴趣,可以查看C ++如何实现迭代器。 在stl向量中,迭代器有一个擦除方法 ,它返回下一个有效的迭代器。
它看起来像这样:
for (itr = listA.begin(); itr != listA.end(); )
{
if ( shouldRemove(*itr) ) {
itr = listA.erase(itr);
}
else {
++itr;
}
}
当然,这个例子不适用于你的问题,因为它都是在C ++中,将新迭代器传播到顶级循环(或者为你的调用添加一个返回值以获得“删除”条件)会很尴尬。 但也许在某处有一个类似的java实现:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.