JDK7新特性 try-with-resources 详细分析
2017-12-09 03:11
543 查看
Try-with-resources是JDK1.7中一个新的异常处理机制,它能够很容易地关闭在try-catch语句块中使用的资源。
try语句块中有可能抛出异常,finally语句块中有一个地方会能出异常。
不论try语句块中是否有异常抛出,finally语句块始终会被执行。这意味着,不论try语句块中发生什么,
假设try语句块抛出一个异常,然后finally语句块被执行。同样假设finally语句块也抛出了一个异常。那么哪个异常会根据调用栈往外传播?
即使try语句块中抛出的异常与异常传播更相关,最终还是finally语句块中抛出的异常会根据调用栈向外传播。
在JDK1.7中,对于上面的例子可以用try-with-resource 结构这样写:
上面的例子在try关键字后的括号里创建了两个资源——
这些资源将按照他们被创建顺序的逆序来关闭。首先
AutoClosable 接口仅仅有一个方法,接口定义如下:
任何实现了这个接口的方法都可以在try-with-resources结构中使用。
其实try-with-resources就是一个语法糖,编译器自动为我们做了一下工作:
当try语句块在执行中遇到异常时,catch语句会捕获到抛出的异常,但并不会马上处理这些异常,编译器会调用实现了AutoCloseable接口的待释放对象的close方法,执行资源的释放工作
当对象的close方法执行时遇到到异常,此时编译器不会直接抛出,而是把产生的异常都记录下来。这么做的好处是不会丢失任何异常。在java7之前,这种做法需要实现自己的异常类,而在java7中,已经对Throwable类进行了修改以支持这种情况。在java7中为Throwable类增加addSuppressed方法。当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过addSuppressed方法把这些被抑制的方法记录下来。被抑制的异常会出现在抛出的异常的堆栈信息中,也可以通过getSuppressed方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。
编译器为我们做的工作大体如下所示
我编写了一个自定义的对象来模拟了一下资源关闭的流程,简单明了
输出结果:
利用Try-Catch-Finally管理资源的释放
在java7以前,程序中使用的资源需要被明确地关闭,我们需要在finally块中编写一大堆繁琐的代码,比如下面这种:BufferedReader reader = null; PrintWriter writer = null; try { reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new PrintWriter(socket.getOutputStream()); //TODO }catch (Exception e){ e.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (writer != null){ writer.close(); } }
try语句块中有可能抛出异常,finally语句块中有一个地方会能出异常。
不论try语句块中是否有异常抛出,finally语句块始终会被执行。这意味着,不论try语句块中发生什么,
reader都会被关闭,或者说都会试图被关闭。如果关闭失败,
reader.close()方法也可能会抛出异常。
假设try语句块抛出一个异常,然后finally语句块被执行。同样假设finally语句块也抛出了一个异常。那么哪个异常会根据调用栈往外传播?
即使try语句块中抛出的异常与异常传播更相关,最终还是finally语句块中抛出的异常会根据调用栈向外传播。
在JDK1.7中,对于上面的例子可以用try-with-resource 结构这样写:
try(BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true) ){ String body; while ((body = reader.readLine()) != null){ String res = body.equalsIgnoreCase("query time") ? new Date().toString() : "Bad order!"; writer.println(res); } }catch (IOException e){ e.printStackTrace(); }
上面的例子在try关键字后的括号里创建了两个资源——
reader和
writer。当程序运行离开try语句块时,这两个资源都会被自动关闭。
这些资源将按照他们被创建顺序的逆序来关闭。首先
writer会被关闭,然后
reader会被关闭。
资源被自动释放的关键:实现Closeable接口
这个try-with-resources结构里不仅能够操作java内置的类。你也可以在自己的类中实现java.lang.AutoCloseable接口,然后在try-with-resources结构里使用这个类。AutoClosable 接口仅仅有一个方法,接口定义如下:
public interface AutoClosable { public void close() throws Exception; }
任何实现了这个接口的方法都可以在try-with-resources结构中使用。
其实try-with-resources就是一个语法糖,编译器自动为我们做了一下工作:
当try语句块在执行中遇到异常时,catch语句会捕获到抛出的异常,但并不会马上处理这些异常,编译器会调用实现了AutoCloseable接口的待释放对象的close方法,执行资源的释放工作
当对象的close方法执行时遇到到异常,此时编译器不会直接抛出,而是把产生的异常都记录下来。这么做的好处是不会丢失任何异常。在java7之前,这种做法需要实现自己的异常类,而在java7中,已经对Throwable类进行了修改以支持这种情况。在java7中为Throwable类增加addSuppressed方法。当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过addSuppressed方法把这些被抑制的方法记录下来。被抑制的异常会出现在抛出的异常的堆栈信息中,也可以通过getSuppressed方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。
编译器为我们做的工作大体如下所示
BufferedReader reader = null; PrintWriter writer = null; try { reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new PrintWriter(socket.getOutputStream()); //TODO }catch (Exception e){ if (reader != null){ try { reader.close(); } catch (IOException e1) { e.addSuppressed(e1); } } if (writer != null){ writer.close(); } e.printStackTrace(); } }
我编写了一个自定义的对象来模拟了一下资源关闭的流程,简单明了
package chp2.bio; import java.io.Closeable; import java.io.IOException; /** * Created by ThinkPad on 2017/12/9. */ public class CloseDemo implements AutoCloseable { public static void main(String[] args) { try(CloseDemo demo = new CloseDemo()) { System.out.println("代码执行出现ClassNotFound异常"); throw new ClassNotFoundException("ClassDemo NotFound exception"); }catch (Exception e){ System.out.println("捕获到异常:" + e.getLocalizedMessage()); System.out.println("异常类型:" + e.getClass().getName()); Throwable[] throwables = e.getSuppressed(); for (Throwable throwable : throwables) { System.out.println("被抑制的异常:" + throwable.getMessage()); System.out.println("被抑制的异常名称:" + throwable.getClass().getName()); } } } @Override public void close() { System.out.println("CloseDemo 开始关闭"); throw new ArrayIndexOutOfBoundsException("关闭demo出现异常"); } }
输出结果:
代码执行出现ClassNotFound异常 CloseDemo 开始关闭 捕获到异常:ClassDemo NotFound exception 异常类型:java.lang.ClassNotFoundException 被抑制的异常:关闭demo出现异常 被抑制的异常名称:java.lang.ArrayIndexOutOfBoundsException
相关文章推荐
- Java7里try-with-resources分析
- java7新特性:Try - with - Resources语句
- Java7里try-with-resources分析
- java7新特性之Try-with-resources (TWR)
- Java7里try-with-resources分析
- Java 7 新特性try-with-resources语句
- Java SE7新特性之try-with-resources语句
- java 7新特性-TWR(Try-with-resources)
- Java SE7新特性之try-with-resources语句
- Java SE7新特性之try-with-resources语句
- Java SE7新特性之try-with-resources语句
- Java SE7新特性之try-with-resources语句
- Java7里try-with-resources分析
- Java SE7新特性之try-with-resources语句
- JDK1.7新特性之try-with-resources和catch多种异常
- Java7里try-with-resources分析(二)
- Java7里try-with-resources分析
- Java新特性之try-with-resources实践
- java新特性之try-with-resources
- Java SE7新特性之try-with-resources语句