我编写了一个类来加载我的应用程序的配置对象并跟踪它们,以便我可以通过单个方法调用轻松地写出更改或重新加载整个配置。但是,每个配置对象在执行IO时可能会抛出异常,但我不希望这些错误取消整个进程,以便让其他对象仍然有机会重新加载/写入。因此,我收集在迭代对象时抛出的所有异常,并将它们存储在循环之后抛出的超级异常中,因为必须仍然处理每个异常,并且必须通知某人究竟出了什么问题。但是,这种方法对我来说有点奇怪。有人用更清洁的解决方案吗?
以下是上述类的一些代码:
public synchronized void store() throws MultipleCauseException
{
MultipleCauseException me = new MultipleCauseException("unable to store some resources");
for(Resource resource : this.resources.values())
{
try
{
resource.store();
}
catch(StoreException e)
{
me.addCause(e);
}
}
if(me.hasCauses())
throw me;
}
答案 0 :(得分:4)
如果你想保留操作的结果,这似乎是你故意进行的操作,那么抛出异常是不对的。一般来说,如果你抛出异常,你的目标应该是不打扰任何事情。
我建议将异常或从它们派生的数据传递给错误处理回调。
public interface StoreExceptionHandler {
void handle(StoreException exc);
}
public synchronized void store(StoreExceptionHandler excHandler) {
for (Resource resource : this.resources.values()) {
try {
resource.store();
} catch (StoreException exc) {
excHandler.handle(exc);
}
}
/* ... return normally ... */
]
答案 1 :(得分:3)
在设计什么以及什么时候应该抛出异常时有指导原则,这个场景的两个相关的原则是:
您将StoreException
翻译为MultipleCauseException
的方式对我来说似乎是合理的,尽管将不同类型的异常合并到一起可能不是最好的主意。遗憾的是,Java不支持通用Throwable
,所以也许唯一的选择就是创建一个单独的MultipleStoreException
子类。
关于尽早抛出异常(你没有做过),我会说在某些情况下弯曲规则是可以的。我觉得延迟投掷的危险是当异常情况不必要地陷入连锁反应时。只要有可能,您希望避免这种情况,并将异常本地化到可能的最小范围。
在您的情况下,如果从概念上考虑将资源存储为多个独立任务是有意义的,那么可以按照您的方式“批处理”异常。然而,在任务具有更复杂的相互依赖关系的其他情况下,将它们全部集中在一起将使分析异常的任务变得更加困难。
在一个更抽象的意义上,在图论理论术语中,我认为将一个节点与多个无子女孩子合并为一个是可以的。将一个完整的大子树,甚至更糟的是一个循环图合并到一个节点中可能是不合适的。