Answers:
我通常这样做:
try {
// Use the resource.
} catch( Exception ex ) {
// Problem with the resource.
} finally {
// Put away the resource.
closeQuietly( resource );
}
别处:
protected void closeQuietly( Resource resource ) {
try {
if (resource != null) {
resource.close();
}
} catch( Exception ex ) {
log( "Exception during Resource.close()", ex );
}
}
Resource
=> Closeable
吗?
我通常使用以下closeQuietly
方法之一org.apache.commons.io.IOUtils
:
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
可以说有点过高,但是如果让异常冒出气泡并且您无法在方法内记录任何内容(例如,因为它是一个库并且您希望让调用代码处理异常和记录),则可能有用:
Resource resource = null;
boolean isSuccess = false;
try {
resource = Resource.create();
resource.use();
// Following line will only run if nothing above threw an exception.
isSuccess = true;
} finally {
if (resource != null) {
if (isSuccess) {
// let close throw the exception so it isn't swallowed.
resource.close();
} else {
try {
resource.close();
} catch (ResourceException ignore) {
// Just swallow this one because you don't want it
// to replace the one that came first (thrown above).
}
}
}
}
更新:我对此进行了更多研究,并从比我更清楚地思考此问题的人那里找到了一篇很棒的博客文章:http : //illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make -mess-of-stream.html 他进一步走了一步,将两个例外合并为一个,在某些情况下我认为这很有用。
ignore
异常
从Java 7开始,您不再需要在finally块中显式关闭资源,而可以使用try -with-resources语法。try-with-resources语句是一个try语句,用于声明一个或多个资源。资源是程序完成后必须关闭的对象。try-with-resources语句可确保在语句末尾关闭每个资源。任何实现java.lang.AutoCloseable的对象(包括所有实现java.io.Closeable的对象)都可以用作资源。
假设以下代码:
try( Connection con = null;
Statement stmt = con.createStatement();
Result rs= stmt.executeQuery(QUERY);)
{
count = rs.getInt(1);
}
如果发生任何异常,将以创建它们的相反顺序在这三个资源上分别调用close方法。这意味着将首先对ResultSetm,然后对Statement,最后对Connection对象,调用close方法。
同样重要的是要知道抑制了自动调用close方法时发生的任何异常。可以通过Throwable类中定义的getsuppressed()方法来检索这些受抑制的异常。
资料来源:https : //docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
忽略发生在“最终”块中的异常通常是一个坏主意,除非人们知道这些异常将是什么以及它们将代表什么条件。在正常try/finally
使用模式中,该try
块将事物置于外部代码不会期望的状态,并且该finally
块将这些事物的状态恢复为外部代码所期望的状态。捕获异常的外部代码通常会期望,尽管有异常,但所有内容都已还原到normal
州。例如,假设一些代码启动了一个事务,然后尝试添加两个记录;“最终”块执行“如果未提交则回滚”操作。调用者可能已为在执行第二个“添加”操作期间发生异常做好了准备,并且可能期望如果捕获到此类异常,则数据库将处于尝试执行任一操作之前的状态。但是,如果在回滚期间发生第二个异常,则如果调用者对数据库状态做出任何假设,则可能会发生不好的事情。回滚失败代表了一个重大危机-不应由仅预期“无法添加记录”异常的代码抓住。
我个人倾向于采用final方法来捕获发生的异常,并将其包装在“ CleanupFailedException”中,这要认识到此类故障是一个主要问题,并且不应轻易捕获此类异常。
一种解决方案,如果两个异常是两个不同的类
try {
...
}
catch(package1.Exception err)
{
...
}
catch(package2.Exception err)
{
...
}
finally
{
}
但是有时您无法避免第二次尝试捕获。例如用于关闭流
InputStream in=null;
try
{
in= new FileInputStream("File.txt");
(..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
}
catch(SQLException err)
{
//handle exception
}
finally
{
//at the end, we close the file
if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
}
为什么要避免额外的障碍?由于finally块包含“正常”操作,这些操作可能会引发异常,并且您希望finally块完全运行,因此您必须捕获异常。
如果您不希望finally块引发异常,并且不知道如何处理该异常(您将仅转储堆栈跟踪),则使异常冒泡到调用堆栈中(从finally中删除try-catch)块)。
如果要减少类型输入,可以实现“全局”外部try-catch块,该块将捕获在finally块中引发的所有异常:
try {
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
} catch (Exception ex) {
...
}
经过大量考虑,我发现以下代码最佳:
MyResource resource = null;
try {
resource = new MyResource();
resource.doSomethingFancy();
resource.close();
resource = null;
} finally {
closeQuietly(resource)
}
void closeQuietly(MyResource a) {
if (a!=null)
try {
a.close();
} catch (Exception e) {
//ignore
}
}
该代码保证以下内容:
如果可以,则应进行测试以避免出现错误情况。
try{...}
catch(NullArgumentException nae){...}
finally
{
//or if resource had some useful function that tells you its open use that
if (resource != null)
{
resource.Close();
resource = null;//just to be explicit about it was closed
}
}
同样,您可能应该只捕获可以从中恢复的异常,如果无法恢复,则将其传播到程序的顶层。如果您无法测试错误条件,则必须像已经完成的那样用try catch块将代码包围起来(尽管我建议仍然捕获特定的预期错误)。
我通常这样做:
MyResource r = null;
try {
// use resource
} finally {
if( r != null ) try {
r.close();
} catch( ThatSpecificExceptionOnClose teoc ){}
}
原理:如果我已经用完资源,而我唯一的问题就是关闭它,那么我就无能为力了。如果我已经用完资源,则杀死整个线程也没有任何意义。
至少对于我来说,这是一种情况,可以安全地忽略该检查的异常。
到今天为止,使用这个习语我还没有任何问题。
try {
final Resource resource = acquire();
try {
use(resource);
} finally {
resource.release();
}
} catch (ResourceException exx) {
... sensible code ...
}
任务完成。没有空测试。单次捕获,包括获取和释放异常。当然,您可以使用Execute Around惯用语,而对于每种资源类型只需编写一次即可。
我遇到过类似的情况,我无法使用try来处理资源,但是我也想处理来自close的异常,而不仅仅是像closeQuietly机制那样记录并忽略它。就我而言,我实际上并没有处理输出流,因此关闭失败比简单流更令人感兴趣。
IOException ioException = null;
try {
outputStream.write("Something");
outputStream.flush();
} catch (IOException e) {
throw new ExportException("Unable to write to response stream", e);
}
finally {
try {
outputStream.close();
} catch (IOException e) {
ioException = e;
}
}
if (ioException != null) {
throw new ExportException("Unable to close outputstream", ioException);
}