Java 7 的try-with-resources新特性

JAVA7新特性:http://www.360doc.com/content/12/1013/23/820209_241325010.shtml

转自:http://www.360doc.com/content/12/1013/23/820209_241324385.shtml
private static void customBufferStreamCopy(File source, File target){
    try (InputStream fis = new FileInputStream(source);
        OutputStream fos = new FileOutputStream(target)){
        byte[] buf = newbyte[8192];
        int i;
        while((i = fis.read(buf))!=-1){
            fos.write(buf, 0, i);
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}
Java 7 中的这个try-with-resources新特性还是让我眼前一亮啊。(上面红色部分)

1.5 try-with-resources语句

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

对于C++程序员来说,程序的内存管理是他们的一项职责。他们需要保证每一块申请的内存都在正确的时候得到了释放。要么在构造函数中申请,在析构函数中释放;要么使用类似智能指针一样的结构来实现资源管理。Java语言把内存管理的任务交给了Java虚拟机,通过自动垃圾回收机制减少了开发人员的很多工作。但是像输入输出流和数据库连接这样的资源,还是需要开发人员手动释放。

在使用资源的时候,有可能会抛出各种异常,比如读取磁盘文件和访问数据库时都可能出现各种不同的异常。而资源管理的一个要求就是不管操作是否成功,所申请的资源都要被正确释放。1.4.3节的代码清单1-10就是资源管理的经典案例,即通过try-catch-finally语句块的finally语句进行资源释放操作。这种方式虽然比较易懂,但是其中包含的冗余代码比较多。

为了简化这种典型的应用,Java 7对try语句进行了增强,使它可以支持对资源进行管理,保证资源总是被正确释放。代码清单1-18给出了一个读取磁盘文件内容的示例。

代码清单1-18 读取磁盘文件内容的示例

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();
        }
    }
}

上面的代码并不需要使用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.sql.ResultSet和java.sql.Statement也继承了该接口。如果希望自己开发的类也能利用try语句的自动化资源管理,只需要实现AutoCloseable接口即可。代码清单1-19给出了一个自定义资源的使用示例,在close方法中可以添加所需要的资源释放逻辑。

代码清单1-19 自定义资源使用AutoCloseable接口的示例

public class CustomResource implements AutoCloseable {
    public void close() throws Exception {
        System.out.println("进行资源释放。");
    }
    public void useCustomResource() throws Exception {
        try (CustomResource resource = new CustomResource()) {
            System.out.println("使用资源。");
        }
    }
}

除了对单个资源进行管理之外,try-with-resources还可以对多个资源进行管理。代码清单1-20给出了try-with-resources语句同时管理两个资源的例子,即经典的文件内容复制操作。

代码清单1-20 使用try-with-resources语句管理两个资源的示例

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);
            }
        }
    }
}

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

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

posted @ 2013-06-05 16:19  eatpockyboy  阅读(490)  评论(0)    收藏  举报