try-finally 和 try-catch-finally 语句
try...catch...finally
语句将异常处理与清理代码结合在一起。finally
块包含将在所有情况下执行的代码。这使它们适用于资源管理和其他类型的清理。
尝试,终于
这是一个更简单(try...finally
)形式的例子:
try {
doSomething();
} finally {
cleanUp();
}
try...finally
的行为如下:
- 执行
try
块中的代码。 - 如果
try
块没有抛出异常:- 执行
finally
块中的代码。 - 如果
finally
块抛出异常,则传播该异常。 - 否则,控制传递到
try...finally
之后的下一个语句。
- 执行
- 如果 try 块中抛出了异常:
- 执行
finally
块中的代码。 - 如果
finally
块抛出异常,则传播该异常。 - 否则,原始异常继续传播。
- 执行
finally
块中的代码将始终执行。 (唯一的例外是如果调用 System.exit(int)
,或者如果 JVM 发生混乱。)因此,finally
块是始终需要执行的正确位置代码; 例如关闭文件和其他资源或释放锁。
try-catch-终于
我们的第二个例子展示了 catch
和 finally
如何一起使用。它还说明清理资源并不简单。
// This code snippet writes the first line of a file to a string
String result = null;
Reader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName));
result = reader.readLine();
} catch (IOException ex) {
Logger.getLogger.warn("Unexpected IO error", ex); // logging the exception
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// ignore / discard this exception
}
}
}
在这个例子中,try...catch...finally
的一整套(假设的)行为太复杂了,不能在这里描述。简单的版本是 finally
块中的代码将始终执行。
从资源管理的角度来看这个:
- 我们在
try
块之前声明资源(即reader
变量),以便它将在finally
块的范围内。 - 通过放置
new FileReader(...)
,catch
能够处理打开文件时抛出的任何IOError
异常。 - 我们需要在
finally
块中使用reader.close()
,因为我们无法在try
块或catch
块中拦截一些异常路径。 - 但是,由于在初始化
reader
之前可能会抛出异常,我们还需要一个明确的null
测试。 - 最后,
reader.close()
调用可能(假设)抛出异常。我们并不关心这一点,但如果我们不在源头捕获异常,我们需要在调用堆栈中进一步处理它。
Version >= Java SE 7
Java 7 及更高版本提供了另一种 try-with-resources 语法 ,可显着简化资源清理。