Java 7 有一个名为try-with-resources的新特性。它是什么?为什么我们应该使用它,在哪里使用它,我们可以在哪里利用这个特性?
该try
声明没有catch
让我感到困惑的障碍。
Java 7 有一个名为try-with-resources的新特性。它是什么?为什么我们应该使用它,在哪里使用它,我们可以在哪里利用这个特性?
该try
声明没有catch
让我感到困惑的障碍。
引入它是因为 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 也一样
如文档中所述:
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 语句是正常完成还是突然完成,它都会被关闭
您可以从这里阅读更多内容。
现在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。
在 Java 中,如果您使用诸如输入或输出流之类的资源,您总是必须在使用后关闭它。它也可以抛出异常,所以它必须在一个try
catch
块中。关闭必须在finally
块中。这至少是 Java 7 之前的方式。这有几个缺点:
null
在关闭它之前检查您的资源是否存在finally
必须包含另一个try
-catch
虽然前两个主要是语法问题,但最后一个更为关键。因此,如果您使用 try-with 语句,您的代码会变得更简洁,最重要的是:您的资源将始终关闭 :-)
优点是您无需显式关闭您在 try-with-resources 语句中定义的资源。JVM 会处理它。它会自动为您关闭这些资源。
通常,开发人员面临的问题是构建 try-catch-finally 块,因为即使在 finally 块中我们关闭了资源,我们也必须使用 try-catch。try-catch-finally 语句有多种结构可以帮助解决这个问题,但是 try-with-resources 语句基本上可以帮助您简化编码结构逻辑。
使用 try-with-resources 的好处:
更易读的代码和易于编写。
自动资源管理。
代码行数减少。
不需要 finally 块来关闭资源。
我们可以在 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
}
}
当在 try-with-resources 中打开多个资源时,它会以相反的顺序关闭它们以避免任何依赖问题。你可以扩展我的资源程序来证明这一点。
你可以试试这个 - 如果资源在 try{} 中初始化,它会自动关闭:
try {
Scanner scanner = new Scanner(new File(csvFile));
while (scanner.hasNext()) {
// do something
}
scanner.close();
}catch(FileNotFoundException fnfe)
{
System.err.println(fnfe.getLocalizedMessage());
}