60

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

try声明没有catch让我感到困惑的障碍。

4

7 回答 7

89

引入它是因为 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 语言规范 14.20.3中所指定)。java.sql.Connection 也一样

于 2013-07-19T06:30:37.273 回答
18

文档中所述

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

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

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

在此示例中,try-with-resources 语句中声明的资源是 BufferedReader。声明语句紧跟在 try 关键字之后的括号内。Java SE 7 及更高版本中的 BufferedReader 类实现了接口 java.lang.AutoCloseable。因为 BufferedReader 实例是在 try-with-resource 语句中声明的,所以无论 try 语句是正常完成还是突然完成,它都会被关闭

您可以从这里阅读更多内容。

于 2013-07-19T06:27:22.743 回答
11

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
}

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

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。

于 2017-08-30T14:51:51.760 回答
6

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

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

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

于 2013-07-19T06:31:25.703 回答
5

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

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

于 2013-07-19T06:39:33.167 回答
1

使用 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 中打开多个资源时,它会以相反的顺序关闭它们以避免任何依赖问题。你可以扩展我的资源程序来证明这一点。

于 2017-02-27T08:20:56.890 回答
-5

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

try {
            Scanner scanner = new Scanner(new File(csvFile));
            while (scanner.hasNext()) {
                 // do something
            }
            scanner.close();
        }catch(FileNotFoundException fnfe)
        {
            System.err.println(fnfe.getLocalizedMessage());
        }
于 2016-08-01T15:20:01.873 回答