资源自动释放是JDK7的一个重大改进。 jdk7提供了try-with-resources,可以自动关闭相关的资源(只要该资源实现了AutoCloseable接口,jdk7为绝大部分资源对象都实现了这个接口)。
try
-with-resources 语句是一个声明了1到多个资源的try语句。资源是指这个try执行完成后必需close掉的对象,比如connection, resultset等。
try
-with-resources 语句会确保在try语句结束时关闭所有资源。实现了java.lang.AutoCloseable
或java.io.Closeable
的对象都可以做为资源。
下面是一个例子,它会从一个文件中读出首行文本,这里使用了
BufferedReader
的实例来读取数据,
BufferedReader
是一个资源,它应该在程序完成时被关闭。
static String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } }
可以看到,由于
被定义在BufferedReader
try
-with-resource 语句中,因此不管try代码块是正常完成或是出现异常,这个BufferedReader
的实例都将被关闭。
而在java7之前的版本中,需要使用finally 代码块来确保资源被关闭(不管try正常完成还是出现异常)。
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { if (br != null) br.close(); } }
以上是JDK7自动关闭的一个总结,实例都是使用的其他人文章里的。看到这些问题,让我心里一动,提出一个我的问题是,
自动释放机制能否区分是正常释放还是异常释放?具体的说,就是这个释放,是try块正常完成了还是出现异常了需要释放?
之所以提出这个问题,就是因为资源释放是代码非常容易出现bug的场景,而异常情况下是否能合理清理资源、释放资源又是其中最最容易出错的地方。
从数据库相关开发的角度看,例如下面的代码:
Connection connection = null; Statement statement = null; try{ connection = pool.getConnection(); statement = connection.createStatemnet(); boolean executionStatus= statement.execute(“query”); }catch(Exception e){ //Block of code for handle the exception e.printStacktrace(); }finally{ try{ statement.close(); connection.close(); }catch(Exception e){ //block of statements for handle exceptions. }
在JDK7中简化成
Connection connection = null; Statement statement = null; try(//请注意这里的小括号,不是大括号 connection = pool.getConnection(); statement = connection.createStatemnet() ) { boolean executionStatus= statement.execute(“query”); }catch(Exception e){ //block of statements for handles the exceptions }
在上面的情况下,如果需要事务控制,变成:
Connection connection = null; Statement statement = null; try(//请注意这里的小括号,不是大括号 connection = pool.getConnection(); statement = connection.createStatemnet() ) { boolean executionStatus= statement.execute(“query”); conn.commit(); }catch(Exception e){ //block of statements for handles the exceptions conn.rollback(); }
正常执行,到最后,需要提交事务;异常关闭,需要先回滚,然后再关闭。这个事务的控制还得要自己写代码才行。
所以对Oracle提供的java.lang.AutoCloseable接口有一些疑问,为什么只是提供了一个这样的接口供实现:
void close()
为什么不是:
normalClose();//正常关闭 errorClose();//异常关闭
如果是接口这样设计和实现,那么开发可以变得非常简单了。
我举的数据库连接只是一个示例(事务是一个,再有一个是
如果出现异常,那么连接很有可能就不能回池了,只能销毁,因为是坏了的连接)。还有很多类似场景,正常关闭和错误关闭都需要外边很多其他额外工作,不简单的是close那么一件事。
如果有这样的接口,那么,在开发过程中,在基础类实现中,前期把这些资源的释放(创建还好说,
释放至关紧要)都设计实现好,把AutoCloseable需要的两个接口(可惜现在Java只有一个)实现好,那么就会很大程度上减少后期团队开发过程中出现错误。