转自:http://www.4byte.cn/learning/84919/java-7-xin-te-xing-zi-dong-zi-yuan-guan-li-arm-he-autoclosable-jie-kou-jiao-cheng.html
Java 7的 try-with-resource
语法的目的是提高Java开发人员的效率,使得他们不需要在编写代码时考虑资源释放问题。大多数的这类"清理"问题是由于异常发生时清理方法没有被调用产生,因此,这篇文章重点看看当异常抛出时 try-with-resource
代码是如何工作的。
来点异常先
我将在上一篇教程的例子中加上下面三个异常:
class OpenException extends Exception{}class SwingException extends Exception{}class CloseException extends Exception{}
为了保持简单性,这篇教程中我们仅关注OpenDoor类。
OpenDoor类
这个版本的OpenDoor
类的每个方法都会抛出异常。构造函数会抛出OpenException
, swing()
方法会抛出SwingException
,close
方法会抛出CloseException
。我说的只是可能下面的代码中,所有的抛出异常部分都被注释了:
class OpenDoor implements AutoCloseable { public OpenDoor() throws Exception { System.out.println("The door is open."); //throw new OpenException() }; public void swing() throws Exception { System.out.println("The door is becoming unhinged."); //throw new SwingException(); } public void close() throws Exception { System.out.println("The door is closed."); // throw new CloseException(); }}
可执行的TryWithResources
类
下面定义TryWithResources
类,请注意catch
块中得e.getClass()
方法。
public class TryWithResources { public static void main(String[] args) throws Exception { try ( OpenDoor door = new OpenDoor() ) { door.swing(); } catch (Exception e) { System.out.println("Is there a draft? " + e.getClass()); } finally { System.out.println("I'm putting a sweater on, regardless. "); } }}
运行上面的代码,如果没有抛出异常的话,输出应该是这样的:
The door is open.The door is becoming unhinged.The door is closed. I'm putting a sweater on, regardless.
当door的构造方法被调用后门被打开,当门被晃动后,门被自动关闭了(try-with-resource
代码的魔法),最后finally
的代码被调用。
别忘了,我们还有三个异常目前被注释掉了,让我们一个个的抛出他们。
在'try-with-resource'初始化代码块的异常(构造函数抛出)
如果OpenDoor
的构造函数抛出异常时会发生什么?close()
方法是否还会被自动调用?让我们来试一下就知道了,去掉构造函数中异常代码的注释:
public OpenDoor() throws Exception { System.out.println("The door is open."); throw new OpenException();}
代码海星的结果如下:
The door is open.Is there a draft? class OpenException I'm putting a sweater on, regardless.
可以看到,当构造函数抛出异常时try-with-resource
代码体部分的代码没有被执行。当声明资源时,如果有异常抛出,可以认为资源并未正确初始化,所以并需要释放资源。然而,需要注意的时,如果其他资源已被正确初始化,那么还是会按照声明相反的顺序调用那些资源的close()
方法。
try-with-resource
代码块中抛出的异常
如果在swing
方法中抛出异常,会发生什么呢?
public void swing() throws Exception { System.out.println("The door is becoming unhinged."); throw new SwingException(); }
上面代码的输出如下:
The door is open.The door is becoming unhinged.The door is closed.Is there a draft? class SwingException I'm putting a sweater on, regardless.
从上面的输出我们可以了解到:
-
OpenDoor
的构造方法被调用了,第一行输出 -
OpenDoor
的swing
方法也被调用了,第二行输出 -
抛出了
SwingException
-
close
方法被调用,第四行输出 -
异常被
catch
块捕获,第五行输出 -
执行
finally
代码块,地六行输出。
只是try-with-resources
代码块的标准行为,尽管会使人很困惑:什么时候会执行close
方法?规则是:任何AutoCloseable
对象的close
方法会在任何catch
块代码之前被执行。
在AutoCloseable
对象的close
方法中抛出异常
如果在AutoCloseable
对象的close
方法中抛出异常又会发生什么呢?运行一下代码看看:
public void close() throws Exception { System.out.println("The door is closed."); throw new CloseException(); }
输出:
The door is open.The door is becoming unhinged.The door is closed.Is there a draft? class CloseException I'm putting a sweater on, regardless.
多个资源对象都抛出异常
上面的文章中我们了解到当try-with-resources
的声明部分、方法体部分以及AutoCloseable
对象的close
方法抛出异常时,try-with-resources
语句的执行规则。但是,如果有两个资源对象都抛出异常又会怎样呢?
先回到基础部分,我们知道我们在资源声明部分初始化多个资源对象,同样,我们知道如果资源对象正常初始化,那么他们也会被正常关闭(调用close
方法)。
现在考虑一个问题,如果声明了两个资源对象,其中一个正常初始化,另一个却抛出异常会怎么发生什么?规则是:如果一个资源对象初始化正常,它的close
方法会被调用,抛出异常的资源对象的close
方法则不会被调用。
所以,假设我们增加了OpenWindow
类:
class OpenWindow implements AutoCloseable { public OpenWindow() { System.out.println("The window is open."); } public void close() throws Exception { System.out.println("The window is closed."); }}
我们修改Man方法在OpenDoor
对象前初始化一个OpenWindow
对象实例,并且没有抛出异常,然后再初始化OpenDoor
实例,OpenDoor
将抛出异常,在这种情况下,正常初始化的OpenWindow
对象的close
方法会被调用,OpenDoor
对象的close
方法则不会被调用,输出如下:
The window is open.The door is open.The window is closed.Is there a draft? class OpenException I'm putting a sweater on, regardless.
你可以看到,任何成功初始化的资源对象都会被正确关闭,反之则不会调用close
方法仅会调用异常处理代码。