目录
  • java try()语句实现try-with-resources异常管理机制
    • 自定义autocloseable实现

java try()语句实现try-with-resources异常管理机制

java7 新增特性,对于try语句块中使用到的资源,不再需要手动关闭,在语句块结束后,会自动关闭,类似于python的with..as的用法。

利用这个特性,需要实现autocloseable接口,只有一个close方法,实现关闭资源的操作。

public interface autocloseable{
    public void close() throws exception;
}

所有的流,都实现了这个接口,可以在try()中进行实例化。自定义的类只要实现了这个接口,也可以使用这个特性。

不使用try-with-resources时,使用的资源要在finally中进行释放

package stream; 
import java.io.file;
import java.io.fileinputstream;
import java.io.ioexception; 
public class teststream { 
    public static void main(string[] args) {
        file f = new file("d:/test.txt");
        fileinputstream fis = null;
        try {
            fis = new fileinputstream(f); 
        } catch (ioexception e) {
            e.printstacktrace();
        } finally {
            // 在finally 里关闭流
            if (null != fis)
                try { 
                    fis.close();
                } catch (ioexception e) {
                    // todo auto-generated catch block
                    e.printstacktrace();
                }
        } 
    }
}

使用try-with-resources时

形式为try(),括号内可以包含多个语句。

package stream;  
import java.io.file;
import java.io.fileinputstream;
import java.io.ioexception;  
public class teststream {  
    public static void main(string[] args) {
        file f = new file("d:/lol.txt");
  
        //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
        try (fileinputstream fis = new fileinputstream(f)) {
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
                system.out.println(b);
            }
        } catch (ioexception e) {
            e.printstacktrace();
        }  
    }
}

自定义autocloseable实现

在testautocloseable的close方法中打印信息

package test; 
public class testautocloseable implements autocloseable{
 public testautocloseable() {
  system.out.println("class testautocloceable");
 }
 public void close() {
  system.out.println("function close() executed");
 }
}

测试代码

package test; 
public class testfeature { 
 public static void main(string[] args) {
  // todo auto-generated method stub
  try(testautocloseable testautocloseable = new testautocloseable()){   
  }
 } 
}

结果close方法被调用

try-with-resources语句优雅的关闭资源

在java编程过程中,如果打开了外部资源(文件、数据库连接、网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们。

因为外部资源不由jvm管理,无法享用jvm的垃圾回收机制,如果我们不在编程时确保在正确的时机关闭外部资源,就会导致外部资源泄露,紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出等诸多很严重的问题。

在java1.7以前,我们关闭资源的方式如下

public class closetest {
    public static void main(string[] args){ 
        fileinputstream fileinputstream = null;
        try {
            fileinputstream = new fileinputstream("file.txt");
            fileinputstream.read();
        } catch (ioexception e) {
            e.printstacktrace();
        }finally {
            if (fileinputstream != null){
                try {
                    fileinputstream.close();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }
    }
}

为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中,关闭资源时可能抛出的异常,于是经典代码就诞生了。

但是,在java1.7版本之后,新增加了一个语法糖,就是try-with-resources语句,

我们先直接上一个demo,方便理解

public class closetest {
    public static void main(string[] args) {
        try (fileinputstream fileinputstream1 = new fileinputstream("file1.txt");
             fileinputstream fileinputstream2 = new fileinputstream("file2.txt")) {
            fileinputstream1.read();
            fileinputstream2.read();
        } catch (ioexception e) {
            e.printstacktrace();
        }
    }
}

将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,java会确保外部资源的close方法被调用。多个语句使用分号断开。

反编译之后我们可以看见

public static void main(string[] args) {
  try {
    fileinputstream inputstream = new fileinputstream(new file("test"));
    throwable var2 = null;
 
    try {
      system.out.println(inputstream.read());
    } catch (throwable var12) {
      var2 = var12;
      throw var12;
    } finally {
      if (inputstream != null) {
        if (var2 != null) {
          try {
            inputstream.close();
          } catch (throwable var11) {
            var2.addsuppressed(var11);
          }
        } else {
          inputstream.close();
        }
      } 
    } 
  } catch (ioexception var14) {
    throw new runtimeexception(var14.getmessage(), var14);
  }
}

通过反编译的代码,大家可能注意到代码中有一处对异常的特殊处理:

var2.addsuppressed(var11);

这是try-with-resource语法涉及的另外一个知识点,叫做异常抑制。当对外部资源进行处理(例如读或写)时,如果遭遇了异常,且在随后的关闭外部资源过程中,又遭遇了异常,那么你catch到的将会是对外部资源进行处理时遭遇的异常,关闭资源时遭遇的异常将被“抑制”但不是丢弃,通过异常的getsuppressed方法,可以提取出被抑制的异常。

源码里面有解释

 /**
     * returns an array containing all of the exceptions that were
     * suppressed, typically by the {@code try}-with-resources
     * statement, in order to deliver this exception.
     *
     * if no exceptions were suppressed or {@linkplain
     * #throwable(string, throwable, boolean, boolean) suppression is
     * disabled}, an empty array is returned.  this method is
     * thread-safe.  writes to the returned array do not affect future
     * calls to this method.
     *
     * @return an array containing all of the exceptions that were
     *         suppressed to deliver this exception.
     * @since 1.7
     */
    public final synchronized throwable[] getsuppressed() {
        if (suppressedexceptions == suppressed_sentinel ||
            suppressedexceptions == null)
            return empty_throwable_array;
        else
            return suppressedexceptions.toarray(empty_throwable_array);
    }

总结

因为不管什么情况下(异常或者非异常)资源都必须关闭,在jdk1.6之前,应该把close()放在finally块中,以确保资源的正确释放。如果使用jdk1.7以上的版本,推荐使用try-with-resources语句。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。