try with resources簡潔的異常捕獲機制


 通過前篇的《Java文件IO流的操作總結》,我們知道了基本輸入輸出流的使用方式,但是每次都需要在finally處關閉流資源,這樣操作起來既啰嗦又麻煩,有沒有更簡潔的方式呢?本篇就來講解jdk1.7引入的try with resources語法糖式寫法。

什么是語法糖

1.之所以稱之為語法糖,給人的感覺就是很甜,很甜。 
2.在相同功能下,語法糖的寫法會讓代碼更加簡潔流暢,代碼更加語義自然。
3.通過編譯器在編譯期間以特定的字節碼或者特定的方式對這些語法做一些處理
4.語法糖雖然不會提供實質性的功能改進,但是它們或能提高性能、或能提升語法的嚴謹性、或能減少編碼出錯的機會。

使用try with resources捕獲異常

待讀取的文件內容

 示例代碼

package com.lingyejun.io;

import java.io.*;

/**
 * Created by Lingye on 2018/9/28 15:03
 */
public class SyntacticSugarTry {

    // 調用有finally的case值
    public static final int OLD_TRY = 1;
    // 調用新式語法糖式的case值
    public static final int SUGAR_TRY = 2;

    /**
     * 根據輸入參數執行不同方法
     *
     * @param type
     * @return
     */
    public InputStream invokeTry(int type) {
        InputStream inputStream = null;
        switch (type) {
            case OLD_TRY:
                inputStream = oldTryCatch();
                break;
            case SUGAR_TRY:
                inputStream = newTryCatch();
                break;
            default:
                System.out.println("error type");
        }
        return inputStream;
    }

    /**
     * 采用舊式的finally寫法
     *
     * @return
     */
    public InputStream oldTryCatch(){
        // 構建文件對象
        File inputFile = new File("D:\\input.txt");
        // 初始化輸入流
        InputStream inputStream = null;
        try {
            // 創建字節輸入流
            inputStream = new FileInputStream(inputFile);
            // 讀取到1KB字節數組中
            byte[] buffer = new byte[12];
            // 讀取數據並放到buffer數組中
            inputStream.read(buffer);
            System.out.println("oldTryCatch讀取輸出"+new String(buffer));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 關閉流過程,也有可能出現異常
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return inputStream;
    }

    /**
     * 采用語法糖式寫法
     *
     * @return
     */
    public InputStream newTryCatch() {
        // 構建文件對象
        File inputFile = new File("D:\\input.txt");
        // 初始化輸入流
        InputStream returnStream = null;
        // try with resource 語法糖式寫法
        try (InputStream inputStream = new FileInputStream(inputFile)) {
            byte[] buffer = new byte[12];
            inputStream.read(buffer);
            System.out.println("newTryCatch讀取輸出"+new String(buffer));
            returnStream = inputStream;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 省略了繁瑣的finally
        return returnStream;
    }

    public static void main(String[] args) {
        SyntacticSugarTry sugarTry = new SyntacticSugarTry();
        InputStream oldStream = sugarTry.invokeTry(OLD_TRY);
        InputStream sugarStream = sugarTry.invokeTry(SUGAR_TRY);
        // 檢查流是否正常關閉
        try {
            // 再次嘗試讀取,檢查是否關閉
            oldStream.read();
        } catch (IOException e) {
            // 已關閉
            System.out.println("oldStream 輸入流已關閉");
        }
        try {
            // 再次嘗試讀取,檢查是否關閉
            sugarStream.read();
        } catch (IOException e) {
            // 已關閉
            System.out.println("sugarStream 輸入流已關閉");
        }
    }
}

查看文件管道的關閉情況

 語法糖式寫法,執行完畢后自動關閉輸入流

查看輸出結果 

 

不難看出,語法糖的使用其實就是讓我們的寫的代碼更簡單,看起來也更容易理解。

使用原理

語法糖是一種幾乎每種語言或多或少都提供過的一些方便程序員開發代碼的語法,它只是編譯器實現的一些小把戲罷了,編譯期間以特定的字節碼或者特定的方式對這些語法做一些處理,開發者就可以直接方便地使用了。這些語法糖雖然不會提供實質性的功能改進,但是它們或能提高性能、或能提升語法的嚴謹性、或能減少編碼出錯的機會。

使用JD-GUI打開上面類的.class編譯文件后會發現編譯過后,編譯器給我們自動加上了資源流的close關閉動作(81行、95行)。

/* Error */
  public InputStream newTryCatch()
  {
    // Byte code:
    //   0: new 49	java/io/File
    //   3: dup
    //   4: ldc 51
    //   6: invokespecial 53	java/io/File:<init>	(Ljava/lang/String;)V
    //   9: astore_1
    //   10: aconst_null
    //   11: astore_2
    //   12: aconst_null
    //   13: astore_3
    //   14: aconst_null
    //   15: astore 4
    //   17: new 55	java/io/FileInputStream
    //   20: dup
    //   21: aload_1
    //   22: invokespecial 57	java/io/FileInputStream:<init>	(Ljava/io/File;)V
    //   25: astore 5
    //   27: bipush 12
    //   29: newarray <illegal type>
    //   31: astore 6
    //   33: aload 5
    //   35: aload 6
    //   37: invokevirtual 60	java/io/InputStream:read	([B)I
    //   40: pop
    //   41: getstatic 29	java/lang/System:out	Ljava/io/PrintStream;
    //   44: new 64	java/lang/StringBuilder
    //   47: dup
    //   48: ldc 102
    //   50: invokespecial 68	java/lang/StringBuilder:<init>	(Ljava/lang/String;)V
    //   53: new 69	java/lang/String
    //   56: dup
    //   57: aload 6
    //   59: invokespecial 71	java/lang/String:<init>	([B)V
    //   62: invokevirtual 74	java/lang/StringBuilder:append	(Ljava/lang/String;)Ljava/lang/StringBuilder;
    //   65: invokevirtual 78	java/lang/StringBuilder:toString	()Ljava/lang/String;
    //   68: invokevirtual 37	java/io/PrintStream:println	(Ljava/lang/String;)V
    //   71: aload 5
    //   73: astore_2
    //   74: aload 5
    //   76: ifnull +55 -> 131
    //   79: aload 5
    //   81: invokevirtual 87	java/io/InputStream:close	()V
    //   84: goto +47 -> 131
    //   87: astore_3
    //   88: aload 5
    //   90: ifnull +8 -> 98
    //   93: aload 5
    //   95: invokevirtual 87	java/io/InputStream:close	()V
    //   98: aload_3
    //   99: athrow
    //   100: astore 4
    //   102: aload_3
    //   103: ifnonnull +9 -> 112
    //   106: aload 4
    //   108: astore_3
    //   109: goto +15 -> 124
    //   112: aload_3
    //   113: aload 4
    //   115: if_acmpeq +9 -> 124
    //   118: aload_3
    //   119: aload 4
    //   121: invokevirtual 104	java/lang/Throwable:addSuppressed	(Ljava/lang/Throwable;)V
    //   124: aload_3
    //   125: athrow
    //   126: astore_3
    //   127: aload_3
    //   128: invokevirtual 82	java/lang/Exception:printStackTrace	()V
    //   131: aload_2
    //   132: areturn
    // Line number table:
    //   Java source line #75	-> byte code offset #0
    //   Java source line #77	-> byte code offset #10
    //   Java source line #79	-> byte code offset #12
    //   Java source line #80	-> byte code offset #27
    //   Java source line #81	-> byte code offset #33
    //   Java source line #82	-> byte code offset #41
    //   Java source line #83	-> byte code offset #71
    //   Java source line #84	-> byte code offset #74
    //   Java source line #85	-> byte code offset #127
    //   Java source line #88	-> byte code offset #131
    // Local variable table:
    //   start	length	slot	name	signature
    //   0	133	0	this	SyntacticSugarTry
    //   9	13	1	inputFile	java.io.File
    //   11	121	2	returnStream	InputStream
    //   13	1	3	localObject1	Object
    //   87	16	3	localObject2	Object
    //   108	17	3	localObject3	Object
    //   126	2	3	e	Exception
    //   15	1	4	localObject4	Object
    //   100	20	4	localThrowable	Throwable
    //   25	69	5	inputStream	InputStream
    //   31	27	6	buffer	byte[]
    // Exception table:
    //   from	to	target	type
    //   27	74	87	finally
    //   17	100	100	finally
    //   12	126	126	java/lang/Exception
  }

參考文章:

https://www.cnblogs.com/jiumao/p/7136369.html

https://blog.csdn.net/Merlin2017/article/details/78075206 


免責聲明!

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



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