首页 > 代码库 > try-with-resources语句

try-with-resources语句

这节讲的是Java7中引入的使用try语句进行资源管理的新用法。这节的内容与上一节介绍的异常处理的关系比较密切。上节中介绍的Throwable中的新方法addSuppressed就是为try-with-resourcces语句添加的。对于资源管理,大多数开发人员都知道的一条原则是:谁申请,谁释放。这些资源涉及操作系统中的主存、磁盘文件、网络连接和数据库连接等。凡是数量有限的、需要申请和释放的实体,都应该纳入到资源管理的范围中来。

在使用资源的时候,有可能会抛出各种异常,比如读取磁盘文件和访问数据库时都可能出现在各种不同的异常。而资源管理的一个要求就是不管操作是否成功,所申请的资源都要被正确释放。上一节中我们有比较典型的资源释放的示例,这里我们要讲一讲java7中对资源管理的增强。Java7中对try语句进行了增强,使它可以支持对资源进行管理,保证资源总是被正确释放。如例:

package test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ResourceBasicUsage {
    public String readFile(String path) throws IOException {
        try(BufferedReader reader = new BufferedReader(new FileReader(path))) {    //注意这里
            StringBuilder builder = new StringBuilder();
            String line = null;
            while((line = reader.readLine()) != null){
                builder.append(line);
                builder.append(String.format("%n"));
            }
            return builder.toString();
        }
    }
    public static void main(String[] args) {
        ResourceBasicUsage usage = new ResourceBasicUsage();
        try {
            System.out.println(usage.readFile("F:/manifest_provider_loophole.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上面的代码并不需要使用finally语句来保证打开的流被正确关闭,这是自动完成的。相对于传统的使用finally语句的做法,这种方式简单得多。开发人员只需要关心使用资源的业务逻辑即可。资源的申请是在try子句中进行的,而资源的释放是自动完成的。在使用try-with-resources语句的时候,异常可能发生在try语句中,也可能发生在释放资源时。如果资源初始化时或try语句中出现异常,而释放资源的操作正常执行,try语句中的异常会被抛出。如果try语句和释放资源都出现了异常,那么最终抛出的异常是try语句中出现的异常,在释放资源时出现的异常会作为被抑制的异常添加进去,即通过Throwable.addSuppressed方法来实现

能够被try语句所管理的资源需要满足一个条件,那就是其java类要实现java.lang.AutoCloseable接口,否则会出现在编译错误。当需要释放资源的时候,该接口的close方法会被自动调用。Java类库中已有不少接口或类继承或实现了这个接口,使得它们可以用在try语句中。在这些已有的常见接口或类中,最常用的就是与I/O操作和数据库相关的接口。与I/O相关的java.io.Closeable继承了AutoCloseable,而与数据库相关的java.sql.Connection、java.sqlResultSet和java.sql.Statement也继承了该接口。如果希望自己开发的类也能利用try语句的自动化资源管理,只需要实现AutoCloseable接口即可。

除了对单个资源进行管理之外,try-with-resources还可以对多个资源进行管理。如例:

package test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class MultipleResourcesUsage {
    public void copyFile(String fromPath,String toPath) throws IOException {
        try(InputStream input = new FileInputStream(fromPath);            //注意,这里用了分号
                OutputStream output = new FileOutputStream(toPath)){
            byte[] buffer = new byte[8192];
            int len = -1;
            while((len = input.read(buffer)) != -1){
                output.write(buffer, 0, len);
            }
        }
    }
    public static void main(String[] args) {
        MultipleResourcesUsage usage = new MultipleResourcesUsage();
        try {
            usage.copyFile("F:/manifest_provider_loophole.txt", "F:/aaa.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

当对多个资源进行管理的时候,在释放每个资源时都可能会产生异常。所有这些异常都会被加到资源初始化异常或try语句块中抛出的异常的被抑制异常列表中。

在try-with-resource语句中也可以使用catch和finally子句。在catch子句中可以捕获try语句块和释放资源时可能发生的各种异常

try-with-resources语句