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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM