【问题标题】:What's the purpose of try-with-resources statements?try-with-resources 语句的目的是什么?
【发布时间】:2013-07-18 08:12:34
【问题描述】:

Java 7 有一个名为try-with-resources 的新特性。它是什么?为什么我们应该使用它,在哪里使用它,我们可以在哪里利用这个功能?

try 语句没有 catch 块,这让我很困惑。

【问题讨论】:

标签: java java-7 try-with-resources


【解决方案1】:

你可以试试这个 - 如果资源在 try{} 中被初始化,它会自动关闭:

try {
            Scanner scanner = new Scanner(new File(csvFile));
            while (scanner.hasNext()) {
                 // do something
            }
            scanner.close();
        }catch(FileNotFoundException fnfe)
        {
            System.err.println(fnfe.getLocalizedMessage());
        }

【讨论】:

    【解决方案2】:

    使用 try-with-resources 的好处:

    1. 代码更易读,更易编写。

    2. 自动资源管理。

    3. 代码行数减少。

    4. 不需要finally阻塞来关闭资源。

    5. 我们可以在try-with-resources语句中打开多个资源,用分号隔开。例如,我们可以编写以下代码。

      public void sampleTryWithResource() {
          try(Connection dbCon = DriverManager.getConnection("url", "user", "password");
                  BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));) {
              //...Your Business logic
          } catch (Exception e) {
              //...Exception Handling
          }
      }
      
    6. 当在 try-with-resources 中打开多个资源时,它会以相反的顺序关闭它们以避免任何依赖问题。你可以扩展我的资源程序来证明这一点。

    【讨论】:

      【解决方案3】:

      Java 9 发布后从 2017 年开始更新

      现在有了Java 9,我们有了更多的语法糖,我们可以在try-catch 块之外声明一个资源,但仍然可以正确处理。

      我们以Java 6 处理资源的方式为例:

      InputStream stream = new MyInputStream(...);
      try {
          // ... use stream
      } catch(IOException e) {
         // handle exception
      } finally {
          try {
              if(stream != null) {
                  stream.close();
              }
          } catch(IOException e) {
              // handle yet another possible exception
          }
      }
      

      在这里我们可以注意到,正如其他答案所指出的那样,这段代码非常丑陋。

      所以Java 7 中的解决方案是引入这个try-catch-with-resource

      try (InputStream stream = new MyInputStream(...)){
          // ... use stream
      } catch(IOException e) {
         // handle exception
      }
      

      这个符号肯定比前一个要好得多,但是我们有一个问题。如果资源(在这种情况下为 stream)之前已经声明过,但我们想确保它在这个块中被正确处理,我们需要这样的技巧:

      InputStream stream = new MyInputStream(...)
      try (InputStream stream2 = stream) {
         // do something with stream being sure that is going to be closed at the end
      } catch(IOException e) {
         // handle exception
      }
      

      我们可以注意到,这种情况只能通过另一段丑陋的代码来解决。这就是 Java 9 改进了 Try-With-Resources 引入新语法的原因:

      InputStream stream = new MyInputStream(...)
      try (stream) {
         // do something with stream being sure that is going to be closed at the end
      } catch(IOException e) {
         // handle exception
      }
      

      请注意,此语法将导致 Java 版本 8 或次要版本的编译时错误

      这是一种更“自然”的编写方式,即使在大多数用例中我们不需要 try 块范围之外的资源。 唯一的限制是 reader 变量应该是有效的 final 或只是 final。

      【讨论】:

        【解决方案4】:

        它是因为Java中使用的一些资源(如SQL连接或流)难以正确处理而引入的;例如,在 java 6 中,要正确处理 InputStream,您必须执行以下操作:

        InputStream stream = new MyInputStream(...);
        try {
            // ... use stream
        } catch(IOException e) {
           // handle exception
        } finally {
            try {
                if(stream != null) {
                    stream.close();
                }
            } catch(IOException e) {
                // handle yet another possible exception
            }
        }
        

        你注意到丑陋的双重尝试了吗?现在使用 try-with-resources 你可以这样做:

        try (InputStream stream = new MyInputStream(...)){
            // ... use stream
        } catch(IOException e) {
           // handle exception
        }
        

        并且 close() 会被自动调用,如果它抛出一个 IOException ,它将被抑制(在Java Language Specification 14.20.3 中指定)。 java.sql.Connection

        也是如此

        【讨论】:

        • 我个人觉得 try-with-resources 语句也很丑陋。当您拥有多个资源时,情况会更糟。
        • @morgano if it throws an IOException, it will be handled in the same catch clause 这是误导。如果close() 抛出异常,则会被抑制。
        • stream 声明为final 并且您不需要检查if(stream != null)(它总是正确的)
        【解决方案5】:

        作为stated in the documentation:

        try-with-resources 语句是一个 try 语句,它声明一个 或更多资源。资源是必须在之后关闭的对象 该程序已完成。 try-with-resources 语句 确保每个资源在语句结束时关闭。任何 实现java.lang.AutoCloseable 的对象,其中包括所有 实现java.io.Closeable 的对象可以用作 资源。

        以下示例从文件中读取第一行。它使用一个 BufferedReader 实例从文件中读取数据。缓冲阅读器 是程序完成后必须关闭的资源 它:

        static String readFirstLineFromFile(String path) throws IOException {
            try (BufferedReader br =
                           new BufferedReader(new FileReader(path))) {
                return br.readLine();
            }
        }
        

        在本例中,try-with-resources 中声明的资源 语句是一个 BufferedReader。声明声明出现 在 try 关键字之后的括号内。班上 BufferedReader,在 Java SE 7 及更高版本中,实现了接口 java.lang.AutoCloseable。因为 BufferedReader 实例是 在 try-with-resource 语句中声明,它将被关闭 不管try语句是正常完成还是突然完成

        您可以从here阅读更多内容。

        【讨论】:

        • 如果 BufferedReader 构造函数抛出异常(不太可能),FileReader 将不会关闭。
        【解决方案6】:

        优点是你不需要显式关闭你在 try-with-resources 语句中定义的资源。 JVM 会处理它。它会自动为您关闭这些资源。

        通常开发人员面临的问题是构建 try-catch-finally 块,因为即使在 finally 块中我们关闭资源的地方我们也必须使用 try-catch。 try-catch-finally 语句有多种结构可以帮助解决这个问题,但是 try-with-resources 语句基本上可以帮助您简化编码结构逻辑。

        【讨论】:

          【解决方案7】:

          在 Java 中,如果您使用诸如输入或输出流之类的资源,您总是必须在使用后关闭它。它还可以抛出异常,因此它必须位于 try catch 块中。关闭必须在finally 块中。这至少是 Java 7 之前的方式。这有几个缺点:

          • 您必须在关闭之前检查您的资源是否为null
          • 关闭本身可能会引发异常,因此您的 finally 必须包含另一个 try - catch
          • 程序员往往会忘记关闭他们的资源

          虽然前两个主要是语法问题,但最后一个更为关键。因此,如果您使用 try-with 语句,您的代码会变得更简洁,最重要的是:您的资源将始终关闭 :-)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-05-21
            • 1970-01-01
            • 2016-04-21
            • 1970-01-01
            • 2022-08-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多