• Java IO 四大附加接口、try-with-resource


    Java IO 四大附加接口、try-with-resource

    @author ixenos

    四大附加接口 Closeable、Flushable、Readable、Appendable


    Closeable:

      void close() throws IOException 关闭此流并释放与此流关联的所有系统资源

      java.io.closeable扩展了java.lang.AutoCloseable,因此,对任何Closeable进行操作时,都可以使用try-with-resources语句

    • try-with-resources 可以声明一个或多个资源,资源之间用分号隔开。
    • 1 try (
      2         java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
      3         java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
      4       ) {
      5             ...
      6       }

      有关 try-with-resource 特性的具体分析请见下文。

    Flushable:

      void flush() 将所有已缓冲输出写入底层流

    Readable:

      int read(CharBuffer cb) 形参中的CharBuffer类拥有按顺序随机地进行读写访问的方法,它表示一个内存中的缓冲区或者一个内存映像(虚拟内存)的文件

      

    Appendable:

      Appendable append(char c) 添加的单个字符

      Appendable append(CharSequence s) 添加字符序列,CharSequence接口描述了一个char值序列的基本属性,StringCharBufferStringBufferStringBuilder都实现了CharSequence,所以可以传入这些类型的对象

      以上两个方法,都返回this

    四大IO抽象类与附加接口的关系


    1、InputStream、OutputStream、Reader、Writer都实现了Closeable和AutoCloseable接口,因此,都可以使用 try-with-resources 语句

    2、OutputStream、Writer实现了Flushable接口

    3、Reader实现了Readable接口

    4、Writer实现了Appendable接口

    try-with-resource


    try-with-resource 是Java SE 7 加入AutoCloseable接口后才有的,closeable接口继承了AutoCloseable接口。

      AutoCloseable接口规定了自动关闭资源:

    The close() method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header.

    1、这个所谓的try-with-resources,是个语法糖。实际上就是自动调用资源的close()函数。

     1 public class TryStudy implements AutoCloseable{  
     2     static void test() throws Exception {  
     3         try(TryStudy tryStudy = new TryStudy()){  
     4             System.out.println(tryStudy);  
     5         }  
     6     }  
     7     @Override  
     8     public void close() throws Exception {  
     9     }  
    10 }  

    2、可以在一个 try-with-resources 语句中声明一个或多个资源(用分号隔开),但要注意资源的 close 方法调用顺序与它们的创建顺序相反 

    1 try (
    2         java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
    3         java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    4       ) 

      资源的close方法在JVM中的调用顺序是: writer.close()   zf.close()

    3、下面从编绎器生成的字节码来分析下,try-with-resources到底是怎样工作的:

      TryStudy实现了AutoCloseable接口,下面来看下test函数的字节码:

     1 static test()V throws java/lang/Exception   
     2   TRYCATCHBLOCK L0 L1 L2   
     3   TRYCATCHBLOCK L3 L4 L4   
     4  L5  
     5   LINENUMBER 21 L5  
     6   ACONST_NULL  
     7   ASTORE 0  
     8   ACONST_NULL  
     9   ASTORE 1  
    10  L3  
    11   NEW TryStudy  
    12   DUP  
    13   INVOKESPECIAL TryStudy.<init> ()V  
    14   ASTORE 2  
    15  L0  
    16   LINENUMBER 22 L0  
    17   GETSTATIC java/lang/System.out : Ljava/io/PrintStream;  
    18   ALOAD 2  
    19   INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V  
    20  L1  
    21   LINENUMBER 23 L1  
    22   ALOAD 2  
    23   IFNULL L6  
    24   ALOAD 2  
    25   INVOKEVIRTUAL TryStudy.close ()V  
    26   GOTO L6  
    27  L2  
    28  FRAME FULL [java/lang/Throwable java/lang/Throwable TryStudy] [java/lang/Throwable]  
    29   ASTORE 0  
    30   ALOAD 2  
    31   IFNULL L7  
    32   ALOAD 2  
    33   INVOKEVIRTUAL TryStudy.close ()V  
    34  L7  
    35  FRAME CHOP 1  
    36   ALOAD 0  
    37   ATHROW  
    38  L4  
    39  FRAME SAME1 java/lang/Throwable  
    40   ASTORE 1  
    41   ALOAD 0  
    42   IFNONNULL L8  
    43   ALOAD 1  
    44   ASTORE 0  
    45   GOTO L9  
    46  L8  
    47  FRAME SAME  
    48   ALOAD 0  
    49   ALOAD 1  
    50   IF_ACMPEQ L9  
    51   ALOAD 0  
    52   ALOAD 1  
    53   INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V  
    54  L9  
    55  FRAME SAME  
    56   ALOAD 0  
    57   ATHROW  
    58  L6  
    59   LINENUMBER 24 L6  
    60  FRAME CHOP 2  
    61   RETURN  
    62   LOCALVARIABLE tryStudy LTryStudy; L0 L7 2  
    63   MAXSTACK = 2  
    64   MAXLOCALS = 3  

    从字节码里可以看出,的确是有判断tryStudy对象是否为null,如果不是null,则调用close函数进行资源回收。

    try-with-resource与异常捕获


    1、从 被丢弃 到 被抑制 的异常 Suppressed Exceptions

      再仔细分析,可以发现有一个Throwable.addSuppressed的调用,那么这个调用是什么呢?

      使用了try-catch语句之后(try-with-resource也算是try-catch),有可能会出现两种异常,一个是try块里的异常,一个是调用close函数里抛出的异常。

      a) 在JDK1.7 以前,一旦finally块抛出了close函数里的异常,前面try块catch的异常被丢弃了!

      b) 而在 try-with-resources 语句中如果在调用close函数时出现异常(注意这个前提),那么前面的异常就被称为Suppressed Exceptions,因此Throwable还有个addSuppressed函数可以把它们保存起来,当用户捕捉到close里抛出的异常时,就可以调用Throwable.getSuppressed函数来取出close之前的异常了。

    2、注意:

       一个 try-with-resources 语句可以像普通的 try 语句那样有 catch 和 finally 块。

      但是在try-with-resources 语句中, 任意的 catch 或者 finally 块都是在声明的资源被关闭以后才运行。

    3、catch多种异常,但抛出一种异常时

      在JDK1.7之前catch多个异常是这样的:

    1         try{
    2         //逻辑代码
    3         }catch (IOException ex) {
    4              logger.log(ex);
    5              throw new SpecialException();
    6         catch (SQLException ex) {
    7              logger.log(ex);
    8              throw new SpecialException();
    9         }

    从上述代码中可以看出这样写非常的难看,并且会出现许多重复的代码。

    JDK1.7及以后可以这样:

    1         try{
    2         //逻辑代码
    3         }catch (IOException | SQLException ex) {
    4              logger.log(ex);
    5              throw new SpecialException();
    6         }

    注:上面例子中的ex是隐式的final不可以在catch块中改变ex。

     4、在JDK1.7以前的版本,在方法声明中声明抛出的异常如果在方法体内没有抛出时不被允许的,如下:

     1 static class FirstException extends Exception { 
     2     
     3 }
     4 
     5 static class SecondException extends Exception {
     6     
     7 }
     8 
     9 public void rethrowException(String exceptionName) throws Exception {
    10     
    11   try {
    12       
    13     if (exceptionName.equals("First")) {
    14         //如果异常名称为"First",则抛出异常一
    15       throw new FirstException();
    16       
    17     } else {
    18         //否则的话,则抛出异常二
    19       throw new SecondException();
    20       
    21     }
    22     
    23   } catch (Exception e) {
    24       
    25     throw e;
    26   }
    27 }

    JDK1.7及以后版本:

     1 static class FirstException extends Exception { 
     2     
     3 }
     4 
     5 static class SecondException extends Exception {
     6     
     7 }
     8 
     9 public void rethrowException(String exceptionName) throws Exception, FirstException, SecondException {
    10     try {
    11       // 逻辑代码
    12     }catch (Exception e) {
    13         
    14       throw e;
    15     }
    16 }
  • 相关阅读:
    gulp+browser-sync使用方法
    小程序试用体验
    移动端调试总结
    函数防抖和函数分流
    页面返回顶部的方法总结
    POJ
    POJ
    UVA 10129 Play on Words(欧拉道路)
    UVA 10305 Ordering Tasks (拓扑排序)
    UVA 12657 Boxes in a Line(双向链表+小技巧)
  • 原文地址:https://www.cnblogs.com/ixenos/p/5849782.html
Copyright © 2020-2023  润新知