深入理解Java基础之try-with-resource语法糖

  


  

  

众所周知,所有被打开的系统资源,比如流,文件或者插座连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故。

  

在Java的江湖中,存在着一种名为最后的功夫,它可以保证当你习武走火入魔之时,还可以做一些自救的操作。在远古时代,处理资源关闭的代码通常写在最后块中。然而,如果你同时打开了多个资源,那么将会出现噩梦般的场景:

        公开课演示{   公共静态void main (String [] args) {   BufferedInputStream本=零;   布特BufferedOutputStream=零;   尝试{   本=new BufferedInputStream(新FileInputStream(新文件(“用法”)));   布特=new BufferedOutputStream(新FileOutputStream(新文件(“out.txt”)));   int b;   在((b=bin.read ()) !=1) {   bout.write (b);   }   }   抓住(IOException e) {   e.printStackTrace ();   }   最后{   如果(本!=null) {   尝试{   bin.close ();   }   抓住(IOException e) {   把e;   }   最后{   如果(布特!=null) {   尝试{   bout.close ();   }   抓住(IOException e) {   把e;   }   }   }   }   }   }   }      

哦,我的上帝! ! !关闭资源的代码竟然比业务代码还要多! ! !这是因为,我们不仅需要关闭<代码> BufferedInputStream> BufferedInputStream> BufferedOutputStream>   

Java 1.7中新增的try-with-resource语法糖来打开资源,而无需码农们自己书写资源来关闭代码。再也不用担心我把手写断掉了!我们用try-with-resource来改写刚才的例子:

        公开课TryWithResource {   公共静态void main (String [] args) {   试(BufferedInputStream本=new BufferedInputStream(新FileInputStream(新文件(“用法”)));   布特BufferedOutputStream=new BufferedOutputStream(新FileOutputStream(新文件(“out.txt”)))) {   int b;   在((b=bin.read ()) !=1) {   bout.write (b);   }   }   抓住(IOException e) {   e.printStackTrace ();   }   }   }      


  

  

为了能够配合try-with-resource,资源必须实现<代码> AutoClosable 接口。该接口的实现类需要重写<代码> 密切方法:

        公共类连接实现AutoCloseable {   公共空间sendData () {   System.out.println(“正在发送数据”);   }   @Override   公共空间close()抛出异常{   System.out.println(“正在关闭连接”);   }   }      之前      

调用类:

        公开课TryWithResource {   公共静态void main (String [] args) {   试(连接康涅狄格州=新连接()){   conn.sendData ();   }   捕获(异常e) {   e.printStackTrace ();   }   }   }      之前      

运行后输出结果:

  
  

正在发送数据
  正在关闭连接

     


  

  

那么这个是怎么做到的呢?我相信聪明的你们一定已经猜到了,其实,这一切都是编译器大神搞的鬼。我们反编译刚才例子的类文件:

        包com.codersm.trywithresource;      公开课TryWithResource {   公共TryWithResource () {   }      公共静态void main (String [] args) {   尝试{   连接康涅狄格州=new连接();   Throwable var2=零;      尝试{   conn.sendData ();   }捕捉(Throwable var12) {   var2=var12;   把var12;   最后}{   如果(康涅狄格州!=null) {   如果(var2 !=null) {   尝试{   conn.close ();   }捕捉(Throwable var11) {   var2.addSuppressed (var11);   }   其他}{   conn.close ();   }   }      }   }捕捉(异常var14) {   var14.printStackTrace ();   }      }   }      之前      

看到没,在第15 ~ 27行,编译器自动帮我们生成了最后块,并且在里面调用了资源附近的方法,所以例子中附近的方法会在运行的时候被执行。

  


  

  

细心的你们肯定又发现了,刚才反编译的代码(第21行)比远古时代写的代码多了一个addSuppressed。为了了解这段代码的用意,我们稍微修改一下刚才的例子:我们将刚才的代码改回远古时代手动关闭异常的方式,并且在sendData和密切的方法中抛出异常:

深入理解Java基础之try-with-resource语法糖