Java try()语句实现try-with-resources异常管理机制操作
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语句。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。