香雨站

用户名  找回密码
 立即注册
帖子
热搜: 活动 交友 discuz
查看: 96|回复: 0

Java中的try-with-resources语句

[复制链接]

4

主题

5

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2023-7-27 13:32:33 | 显示全部楼层 |阅读模式
介绍

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。很容易忘记在编码几个小时后关闭您的资源之一,或者在随机激发灵感后忘记关闭刚刚添加到程序中的资源。
该代码更具可读性,更易于更改和维护,并且通常更短。
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|香雨站

GMT+8, 2025-3-16 03:01 , Processed in 0.374598 second(s), 32 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.. 技术支持 by 巅峰设计

快速回复 返回顶部 返回列表