我无法在Java中找到任何关于catch块的建议,这些建议涉及一些本身可能会抛出异常的清理操作。
经典的例子是我们通常在stream.close()
子句中调用的finally
,如果抛出异常,我们要么通过在try-catch块中调用它来忽略它,要么将它声明为被重新抛出。
但总的来说,我如何处理以下案件:
public void doIt() throws ApiException { //ApiException is my "higher level" exception
try {
doLower();
} catch(Exception le) {
doCleanup(); //this throws exception too which I can't communicate to caller
throw new ApiException(le);
}
}
我能做到:
catch(Exception le) {
try {
doCleanup();
} catch(Exception le1) {
//ignore?
//log?
}
throw new ApiException(le); //I must throw le
}
但这意味着我将不得不进行一些日志分析,以了解清理失败的原因。
如果我这样做了:
catch(Exception le) {
try {
doCleanup();
} catch(Exception le1) {
throw new ApiException(le1);
}
这会导致失去le
让我在第一个位置的拦截区。
人们在这里使用的一些习语是什么?
答案 0 :(得分:3)
首先,确定你是否真的需要从finally块中抛出 - 仔细考虑一下 - 在close()调用失败的情况下......好吧,记录它很好 - 但是什么可以更高层你的API真的能解决这个问题吗?因此,对于99%的情况,您将记录次要,然后重新抛出主要。
接下来,如果您确实需要抛出辅助节点,请确定辅助异常的各种原因是否重要。它们很少见。因此,将辅助的原因设置为主要(使用适当的构造函数或initCause())。
最后,如果您必须抛出辅助节点,并保留辅助节点和主节点的完整堆栈跟踪 - 那么您将创建一个自定义异常来处理这种情况。这很丑陋,因为您可能希望从不同的父类派生。如果出现这种情况,我建议创建一个辅助类,它能够填充目标异常的堆栈跟踪,以便根据两个异常生成有意义的跟踪(确保对辅助使用缩进,因此嵌套异常是容易拉开。
但大多数情况下,我建议您使用log-and-rethrow-primary范例。专注于修复主要问题,而次要问题通常会自行解决(这里的典型例子是一个IO异常,它会严重影响到对close()的调用也不会成功)。
答案 1 :(得分:0)
使用finally块。如果您担心吞咽堆栈跟踪,请执行以下操作:
Exception ex = new Exception(le.stackTrace());