增强 try (Try-with-resources)

此心光明,亦复何言

Try-with-resources

Try-with-resources是Java7出现的一个新的异常处理机制,它能够很容易地关闭在try-catch语句块中使用的资源。

传统的关闭资源方式是利用Try-Catch-Finally管理资源(旧的代码风格) 即在Java7以前程序中使用的资源需要被明确地关闭。

private static void printFile() throws IOException {
    InputStream input = null;
    try{
        input = new FileInputStream("d:\\hello.txt");
        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    } finally {
        if(input != null){
            input.close();
        }   
    }       
}

以上程序 try语句块中有3处能抛出异常,finally语句块中有一处会抛出异常。

不论try语句块中是否有异常抛出,finally语句块始终会被执行。这意味着,不论try语句块中发生什么,InputStream 都会被关闭,或者说都会试图被关闭。如果关闭失败,close()方法也可能会抛出异常。

假设try语句块抛出一个异常,然后finally语句块被执行。同样假设finally语句块也抛出了一个异常。那么哪个异常会根据调用栈往外传播?

即使try语句块中抛出的异常与异常传播更相关,最终还是finally语句块中抛出的异常会根据调用栈向外传播。

在Java7以后,对于上面的例子可以用try-with-resource 结构这样写:

private static void printFileJava7() throws IOException {
    try(FileInputStream input = new FileInputStream("d:\\hello.txt")) {
        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    }   
}

注意方法中的第一行:

try(FileInputStream input = new FileInputStream("d:\\hello.txt"))

这就是try-with-resource 结构的用法。FileInputStream 类型变量就在try关键字后面的括号中声明。而且一个FileInputStream 类型被实例化并被赋给了这个变量。

当try语句块运行结束时,FileInputStream 会被自动关闭。这是因为FileInputStream 实现了java中的java.lang.AutoCloseable接口。所有实现了这个接口的类都可以在try-with-resources结构中使用。

当try-with-resources结构中抛出一个异常,同时FileInputStream被关闭时(调用了其close方法)也抛出一个异常,try-with-resources结构中抛出的异常会向外传播,而FileInputStream被关闭时抛出的异常被抑制了。这与文章开始处利用旧风格代码的例子(在finally语句块中关闭资源)相反。

使用多个资源

你也可以在块中使用多个资源而且这些资源都能被自动地关闭。下面是例子:

private static void printFileJava7() throws IOException {
    try(FileInputStream input = new FileInputStream("d:\\hello.txt"); BufferedInputStream bufferedInput = new BufferedInputStream(input))
    {
        int data = buffereInput.read();
        while(data != -1){
            System.out.println( (char) data);
            data = bufferedInput.read();
        }
    }
}

上面的例子在try关键字后的括号里创建了两个资源——FileInputStream 和BufferedInputStream。当程序运行离开try语句块时,这两个资源都会被自动关闭。

这些资源将按照他们被创建顺序的逆序来关闭。首先BufferedInputStream 会被关闭,然后FileInputStream会被关闭。

自定义AutoCloseable 实现

这个try-with-resources结构里不仅能够操作java内置的类。你也可以在自己的类中实现java.lang.AutoCloseable接口,然后在try-with-resources结构里使用这个类。

AutoClosable 接口仅仅有一个方法,接口定义如下:

public interface AutoClosable{
    public void close() throws Exception;
}

任何实现了这个接口的方法都可以在try-with-resources结构中使用。下面是一个简单的例子:

public class MyAutoClosable implements AutoClosable{
    public void doIt(){
        System.out.println("MyAutoClosable doing it!");
    }

    @Override
    public void close() throws Exception{
        System.out.println("MyAutoCloseable Closed!");
    }
}

下面是MyAutoClosable 在try-with-resources结构中使用的例子:

private static void myAutoClosable() throws Exception{
    try(MyAutoClosable myAutoClosable = new MyAutoClosable()){
        myAutoClosable.doIt();
    }
}

当方法myAutoClosable.doIt()被调用时,下面是打印到System.out的输出:

MyAutoClosable doing it!
MyAutoClosable closed!

通过上面这些你可以看到,不论try-catch中使用的资源是自己创造的还是java内置的类型,try-with-resources都是一个能够确保资源能被正确地关闭的强大方法。

小结:

  • 自动关闭资源的try语句相当于包含了隐式的finally块(用于关闭资源),因此这个try语句可以既没有catch块,也没有finally块。

  • 被自动关闭的资源必须实现Closeable或AutoCloseable接口。(Closeable是AutoCloseable的子接口,Closeeable接口里的close()方法声明抛出了IOException,;AutoCloseable接口里的close()方法声明抛出了Exception)

    • Java7几乎把所有的“资源类”(包括文件IO的各种类,JDBC编程的Connection、Statement等接口……)进行了改写,改写后的资源类都实现了AutoCloseable或Closeable接口
  • Java7新增的自动关闭资源的try语句允许在try关键字后紧跟一对圆括号,里面可以声明、初始化一个或多个资源,此处的资源指的是那些必须在程序结束时显示关闭的资源(数据库连接、网络连接等),try语句会在该语句结束时自动关闭这些资源。

    • 被关闭的资源必须放在try语句后的圆括号中声明、初始化。如果程序有需要自动关闭资源的try语句后可以带多个catch块和一个finally块。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  •  try-with-resources语句是一个声明一个或多个资源的 try 语句。一个资源作为一个对象,必须在程...
    xdoyf阅读 3,484评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,156评论 19 139
  • 转载自:http://mp.weixin.qq.com/s/LO1yyFeUA6pR_YPyfDoSig 姓名:梅...
    虐先森阅读 1,458评论 0 1
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,806评论 18 399
  • 原始文件README.MD: 修改文件 首先我们查看一下仓库状态: 我们做出这样的修改: 仅仅在原始文件中加了个....
    Josaber阅读 33,982评论 5 9