finally 块本身并不直接释放资源,但它提供了一个保证执行的代码块,我们在这个代码块中手动编写释放资源的代码。
简单来说:finally 块是释放资源的'黄金位置',我们在这里手动关闭文件、数据库连接、网络连接等。
1. 为什么需要 finally?
程序在运行时可能会发生异常(Exception)。当异常被抛出时,程序会中断当前的执行流程,跳转到能够处理该异常的 catch 块。这会导致一个严重问题:在异常发生点之后的代码可能没有机会执行。
考虑一个没有 finally 的场景:
public void readFile() {
FileInputStream file = null;
try {
file = new FileInputStream("myfile.txt"); // 1. 打开文件资源
// ... 读取文件,假设这里发生了 IOException
// 2. 使用资源
file.close(); // 3. 关闭资源 - 如果上面发生异常,这行代码永远执行不到!
} catch (IOException e) {
e.printStackTrace();
}
// 文件描述符未被关闭,资源泄漏!
}
在上面的代码中,如果在'读取文件'时发生异常,程序会立刻跳转到 catch 块,file.close() 这行代码就被跳过了。这个文件句柄/描述符就一直没有被释放,导致资源泄漏。如果这种情况发生多次,可能会耗尽系统资源(如可用的文件句柄数量),导致程序甚至系统崩溃。
2. finally 如何解决问题?
finally 块的关键特性是:无论 try 块中是否发生异常,也无论是否被 catch 捕获,甚至 try 块中有 return 语句,finally 块中的代码都保证会执行。
因此,我们把释放资源的代码放在 finally 块中,确保万无一失。
public void readFile() {
FileInputStream file = null;
try {
file = new FileInputStream("myfile.txt"); // ...
// 读取文件,可能发生异常
} (IOException e) {
e.printStackTrace();
} {
(file != ) {
{
file.close();
} (IOException e) {
e.printStackTrace();
}
}
}
}


