|
介绍
try-with-resources是tryJava中的几条语句之一,旨在减轻开发人员释放try块中使用的资源的义务。
它最初是在Java 7中引入的,其背后的全部想法是,开发人员无需担心仅在一个try-catch-finally块中使用的资源的资源管理。这是通过消除对finally块的需要而实现的,实际上,开发人员仅在关闭资源时才使用块。
此外,使用try-with-resources的代码通常更清晰易读,因此使代码更易于管理,尤其是当我们处理许多try块时。
语法
try-with-resources的语法几乎与通常的try-catch-finally语法相同。唯一的区别是括号后try,我们在其中声明将使用的资源:
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(fileName));
writer.write(str); // do something with the file we've opened
} catch (IOException e) {
// handle the exception
} finally {
try {
if (writer != null)
writer.close();
} catch (IOException e) {
// handle the exception
}
}使用try-with-resources编写的相同代码如下所示:
try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){
writer.write(str); // do something with the file we've opened
}
catch(IOException e){
// handle the exception
}Java理解此代码的方式:
在try语句之后在括号中打开的资源仅在此处和现在需要。.close()在try块中完成工作后,我将立即调用它们的方法。如果在try块中抛出异常,无论如何我都会关闭这些资源。 在引入此方法之前,关闭资源是手动完成的,如之前的代码所示。这本质上是样板代码,并且代码库中乱七八糟,从而降低了可读性并使它们难以维护。
在catch与finally部分试-与资源按预期方式工作,与catch块处理各自的异常和finally不管是否有异常或不执行块。唯一的区别是抑制的异常,这些异常将在本文结尾处进行说明。
注意:从Java 9开始,没有必要在try-with-resources语句中声明资源。我们可以这样做:
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
try (writer) {
writer.write(str); // do something with the file we've opened
}
catch(IOException e) {
// handle the exception
}Multiple Resources
try-with-resources的另一个好方面是添加/删除我们正在使用的资源的简便性,同时确保在完成后它们将被关闭。
如果要使用多个文件,则可以在try()语句中打开文件,并用分号将它们分开:
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
Scanner scanner = new Scanner(System.in)) {
if (scanner.hasNextLine())
writer.write(scanner.nextLine());
}
catch(IOException e) {
// handle the exception
}然后,Java会小心地调用.close()我们在中打开的所有资源try()。
注意:它们以相反的声明顺序关闭,这意味着,在我们的示例中,scanner它将在之前关闭writer。
支持的类
声明的所有资源try()必须实现该AutoCloseable接口。这些通常是各种类型的编写器,读取器,套接字,输出或输入流等resource.close()。使用完所有需要编写的内容。
当然,这包括实现该AutoClosable接口的用户定义对象。但是,您很少会遇到想要编写自己的资源的情况。
万一发生这种情况,您需要实现AutoCloseable或Closeable(仅在此处保持向后兼容性,最好使用AutoCloseable)接口并重写该.close()方法:
订阅我们的新闻
在收件箱中获取临时教程,指南和作业。从来没有垃圾邮件。随时退订。
订阅电子报
订阅
public class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
// close your resource in the appropriate way
}
}异常处理
如果从Java try-with-resources块中引发异常,则在该块的括号内打开的任何资源try仍将自动关闭。
如前所述,try-with-resources的工作原理与try-catch-finally相同,只是增加了一点点。这种增加称为抑制异常。这是不是有必要了解为了使用抑制异常的try-与资源,但阅读他们可能会为在没有其他似乎调试工作是有用的。
想象一个情况:
- 由于某些原因,try-with-resources块中发生异常
- Java在try-with-resources块中停止执行,并调用.close()在中声明的所有资源try()
- 其中一种.close()方法引发异常
- catch块会“捕获”哪个异常?
这种情况向我们介绍了上述抑制的例外。受抑制的异常是一种异常,当在try-with-resources块的隐式finally块中引发该异常时,也可以忽略该异常,如果从该try块也引发了异常。
这些异常是.close()方法中发生的异常,它们的访问方式不同于“常规”异常。
重要的是要了解执行顺序为:
- 资源尝试块
- 最终隐式
- 捕获块(如果在[1]和/或[2]中引发了异常)
- (明确)终于
例如,这是一个除了抛出异常外什么都不做的资源:
public static class MyResource implements AutoCloseable {
// method throws RuntimeException
public void doSomething() {
throw new RuntimeException("From the doSomething method");
}
// we'll override close so that it throws an exception in the implicit finally block of try-with-resources (when it attempts to close our resource)
@Override
public void close() throws Exception {
throw new ArithmeticException("I can throw whatever I want, you can't stop me.");
}
}
public static void main(String[] arguments) throws Exception {
// declare our resource in try
try (MyResource resource = new MyResource()) {
resource.doSomething();
}
catch (Exception e) {
System.out.println("Regular exception: " + e.toString());
// getting the array of suppressed exceptions, and its length
Throwable[] suppressedExceptions = e.getSuppressed();
int n = suppressedExceptions.length;
if (n > 0) {
System.out.println("We've found " + n + " suppressed exceptions:");
for (Throwable exception : suppressedExceptions) {
System.out.println(exception.toString());
}
}
}
}此代码是可运行的。您可以使用它来尝试使用多个MyResource对象,或查看try-with-resources不会抛出异常但.close()会抛出异常的情况。
提示:突然,关闭资源时引发的异常开始变得很重要。
需要特别注意的是,万一尝试关闭资源时引发资源异常,在同一try-with-resources块中打开的任何其他资源仍将关闭。
要注意的另一个事实是,在该try块没有引发异常的情况下,并且尝试.close()使用所使用的资源时引发了多个异常,第一个异常将在调用堆栈中传播,而其他异常将被抑制。 。
正如您在代码中看到的那样,您可以通过访问Throwable返回的数组来获取所有抑制的异常的列表Throwable.getSuppressed()。
请记住,在try块内只能抛出一个异常。引发异常后,将立即退出try块代码,并且Java尝试关闭资源。
结论
应尽可能使用try-with-resources代替常规try-catch-finally。很容易忘记在编码几个小时后关闭您的资源之一,或者在随机激发灵感后忘记关闭刚刚添加到程序中的资源。
该代码更具可读性,更易于更改和维护,并且通常更短。 |
|