我有一些方法使用了一些应该在最后关闭的资源,方法本身和资源关闭可能会抛出所有东西,包括IO连接等异常,一些运行时异常,甚至错误(继承Throwable OOM的所有东西都是常有的情况)。).我想在不丢失信息的情况下处理所有异常,并向客户端发送/抛出最重要的异常(假设是运行时异常/错误?)这是我使用的模式(它是java 1.5,所以我不能使用1.7中的资源功能):
Throwable thr=null;
try {
methodThatCouldThrowCheckedExceptionAndErrorAndRuntimeExcpetion();
log("method succesfully executed.");
} catch (IKnowThisException ikte) {
//Exception will be not lost
log("Method was not executed ,and I can suggest further actions",itke);
thr=ikte;
} catch (Throwable t) {
// This exception will be not lost too
log("Method was not executed ,and I don't know why.",t);
thr=t;
} finally {
try{
// The method below - of course contains the standard null checkers.
closeResourcesMethodThatCouldThrowEverythingToo();
log("resources were closed.");
} catch (IKnowThisEscpetionToo iktet) {
log(iktet);
throw new IllegalStateException("Resources were not closed , because of the known exception and I can suggest some actions" , ijtet);
} catch (Throwable t) {
log(t);
throw new IllegalStateException("Resources were not closed and I don't know why" , t);
}
// in case resources are closed we can re-throw exception from try{} block
if ( thr != null ) {
throw thr;
}
}
但我不完全确定这是最好的方法。这是我发现的类似方法。但它不处理未检查的异常(我需要处理它们吗?)是否存在丢失有价值信息的情况?在大多数示例中,我发现对Errors/RuntimeExcpetions没有做任何特别的处理,但我希望将它们记录下来。有更好的方法吗?也许我应该构造一个更复杂的链式异常来保持信息的紧凑性?
要保留所有错误,最好使用自定义异常类,该类提供类似ARM的"抑制异常"集合的功能。
如果该方法抛出异常,则这是主要异常的原因。如果关闭资源会引发其他异常,则这些异常会作为抑制的异常添加到主异常中。
如果方法完成时没有失败,但关闭资源会引发异常,则第一个异常将成为主异常,随后的资源关闭失败将作为抑制异常添加到该方法中。
如果某个资源具有写入文件或更新数据库等副作用,则应用程序需要确定关闭该资源失败时该怎么办。使用隐藏这些资源关闭异常的通用机制将不允许应用程序做出该决定,并且只有在应用程序不关心是否实际产生任何输出的极少数情况下才有用。
我将研究编译器如何在Java1.7中重写try-with-resources模式。下面是源代码级别1.7中模式的一个简单示例,后面是一个反编译版本,禁用了try和resources sugaring:
// Original:
public void test() throws IOException {
try (final StringWriter writer = new StringWriter()) {
writer.write("This is only a test.");
}
}
// Decompiled:
public void test() throws IOException {
final StringWriter writer = new StringWriter();
Throwable t = null;
try {
writer.write("This is only a test.");
}
catch (Throwable t2) {
t = t2;
throw t2;
}
finally {
if (writer != null) {
if (t != null) {
try {
writer.close();
}
catch (Throwable t2) {
t.addSuppressed(t2);
}
}
else {
writer.close();
}
}
}
}
遗憾的是,addSuppressed()
方法只在Java1.7中引入,但正如@erickson在他的回答中所建议的那样,您可以创建一个引入这种行为的自定义异常类。如果只发生一个异常,只需重新引发该异常即可。否则,请将其替换为自定义异常,将原始异常包装为原因,并添加关闭资源期间发生的任何抑制的异常。
正如我所知,不应该处理未检查的异常。但您可以通过在最终阻塞之前捕获更广泛的异常(如"exception")来进行处理。
我建议你阅读我的博客文章《自我清理》(抓住我的Close课程),然后阅读
import static com.frischcode.util.Close.close;
// Where ... is any number of things to close (in finally block - naturally).
close(...);