Java 7之前
在Java 7之前,在使用一些资源的类时,如BufferedReader,我们要常常提醒自己,必须要在finally块关闭资源。
Java 6示例
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:\\test.txt"));
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
在Java 6的这个示例里,这段代码有几点不好:
- 代码冗长,不可读
- 在finally块了还需要对close()方法添加try-catch
- 在调用close()前,总要判断Reader是否为null
- 如果忘了在finally关闭资源,容易造成资源泄漏
Java 7
Java 7新增了try-with-resoureces自动管理资源的语法。
Java 7示例
try (BufferedReader br = new BufferedReader(new FileReader("C:\\test.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
这短短的几行代码很优雅地解决了Java 7之前对资源管理存在的问题。 在try()里声明的资源,用户不需要手动关闭资源,它会在用完后自动关闭。这样不需要在关闭资源时的try-catch以及检查资源是否为null,也很好避免了因为忘记关闭资源可能导致的资源泄漏。
Java 7的try-with-resources语法需要符合以下规则:
- 资源类需要实现java.lang.AutoCloseable接口
- 资源变量必须在try()声明为本地变量。
- 如果资源在Try-With-Resources语句外声明,那么必须在try()里使用本地变量引用外部声明的资源变量
以下例子不正确
BufferedReader br = new BufferedReader(new FileReader("C:\\test.txt"))
try (br) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
需要改为
BufferedReader br = new BufferedReader(new FileReader("C:\\test.txt"))
try (BufferedReader localReader = br) { //重新引用为本地变量
System.out.println(localReader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
这也算是Java 7/8的Try-With-Resouces bug。
Java 9
Try-With-Resouces在Java 9的改进就是针对Java7/8里资源必须在try()里声明的问题做的修改。
Java 9改进后的Try-With-Resouces允许资源在Try-With-Resouces外部声明,且不需要在try()里重新引用。
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
try (reader) {
System.out.println(reader.readLine());
}