Java 类库中包括许多必须通过调用 close 方法来手工关闭的资源 。 例如 InputStream 、OutputStream 和 java.sql.Connection 。 客户端经常会忽略资源 的关闭 ,造成严重的性能后果也就可想而知了 。 虽然这其中的许多资源都是用终结方法作为安全网,但是效果并不理想。
根据经验,try -finally 语句是确保资源会被适时关闭的最佳方法,就算发生异常或者返回也一样 :
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
这看起来好像也不算太坏,但是如果再添加第二个资源,就会一团糟了 :
static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src) ;
try {
OutputStream out = new FileOutputStream(dst) ;
try {
byte[] buf = new byte[BUFFER_ SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf,0,n);
} finally {
out.close();
}
} finally {
in.close() ;
}
}
这可能令人有点难以置信,不过就算优秀的程序员也会经常犯这样的错误 。
即使用 try-finally 语句正确地关闭了资源,如前两段代码范例所示,它也存在着些许不足 。 因为在 try 块和 finally 块中的代码,都会抛出异常 。 例如在 firstLineOfFile方法中,如果底层的物理设备异常,那么调用 readLine 就会抛出异常,基于同样的原因,调用 close 也会出现异常 。 在这种情况下,第二个异常完全抹除了第一个异常 。 在异常堆枝轨迹中,完全没有关于第一个异常的记录,这在现实的系统中会导致调试变得非常复杂,因为通常需要看到第一个异常才能诊断出问题何在 。 虽然可以通过编写代码来禁止第二个异常,保留第一个异常,但事实上没有人会这么做,因为实现起来太烦琐了 。
当 Java 7 引人 try -with-rsources 语句时,所有这些问题一下子就全部解决了 。 要使用这个构造的资源,必须先实现 AutoCloseable 接口,其中包含了单个返回 void 的 close 方法 。Java 类库与第三方类库中的许多类和接口,现在都实现或扩展了AutoCloseable 接口 。 如果编写了 一个类,它代表的是必须被关闭的资源,那么这个类也应该实现 AutoCloseable 。
以下就是使用 try-with-resources 的第一个范例:
static String firstLineOfFile(String path) throws I0Exception {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
以下是使用 try -with -resources 的第二个范例:
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_ SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf,0,n);
}
}
使用 try-with-resources 不仅使代码 变得更简洁易懂,也更容易进行诊断 。以 firstLineOfFile 方法为例,如果调用 readLine 和(不可见的) close 方法都抛出异常,后一个异常就会被禁止,以保留第一个异常 。 事实上,为了保留你想要看到的那个异常,即便多个异常都可以被禁止 。 这些被禁止的异常并不是简单地被抛弃了,而是会被打印在堆枝轨迹中,并注明它们是被禁止的异常 。 通过编程调用 getSuppressed 方法还可以访问到它们,getsuppres sed 方法也已经添加在 Java 7 的 Throwable 中了 。
在try-with-resources语句中还可以使用catch子句,就像在平时的try-finally语句中一样。这样既可以处理异常,又不需要再套用一层代码。下面举一个稍费了点心思的范例,这个firstLineOfFile方法没有抛出异常,但是如果它无法打开文件,或者无法从中读取,就会返回一个默认值:文章来源:https://www.toymoban.com/news/detail-554050.html
static String firstLineOfFile(String path, String defaultVal) {
try (BufferedReader br = new BufferedReader(
new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
结论很明显:在处理必须关闭的资源时,始终要优先考虑用 try-with-resources ,而不是用 try-finally 。 这样得到的代码将更加简洁、清晰,产生的异常也更有价值 。 有了 try-with-resources 语句,在使用必须关闭的资源时,就能更轻松地正确编写代码了 。 实践证明,这个用 try-finally 是不可能做到的 。文章来源地址https://www.toymoban.com/news/detail-554050.html
到了这里,关于Effective Java笔记(9)try-with-resources 优先于 try -finally的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!