Java自動化資源關閉利器 - try-with-resource使用實踐

在JDK 7中,引入了try-with-resource用於替代在try-catch-finally中手動的資源關閉

通常需要我們手動釋放的資源包括:

  • 文件/流資源
  • socket資源
  • 數據庫連接資源

這些資源不能自動的被回收,長時間無效佔用,當超過最大限制後,將會無資源可用,最終導致系統無法正常運行

以文件拷貝爲例演示JDK 7之前和引入try-with-resource後的差異

  • 使用try-catch-finally實現文件拷貝的資源管理
    輸入輸出流需要在try塊外先定義,並在finally中按初始化順序的倒序逐一進行釋放
	@Test
    public void copyFile() {
        //路徑
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";
        //資源對象
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        try {
            //初始化資源對象
            fileInputStream = new FileInputStream(originalUrl);
            fileOutputStream = new FileOutputStream(outUrl);

            int content;
            //讀取並寫入
            while ((content = fileInputStream.read()) != -1) {
                fileOutputStream.write(content);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//資源關閉
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream!= null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

使用try-with-resource實現文件拷貝的資源管理
try-with-resource的結構是:

		try (
                //資源定義

        ) {
                //邏輯代碼
        } catch(Exception e) {
                //異常處理
        }

try-catch-finally相比,在try後多了一對小括號用於資源定義,且不需要再手動的關閉資源了

具體代碼如下:

	/**
     * 基於JDK7及以後的
     * try - with - resource
     */
    @Test
    public void newCopyFile() {
        //路徑
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";

        /**
         * 小括號內定義資源,不需要顯示的關閉資源,會自動的關閉
         * try - with - resource
         */
        try (
                //定義資源
                FileInputStream fileInputStream = new FileInputStream(originalUrl);
                FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
        ) {
            int content;
            while ((content = fileInputStream.read()) != -1) {
                fileOutputStream.write(content);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

從上面兩段代碼可以看出,在try-with-resource中的小括號內定義資源就不用再手動的進行釋放了

爲了更清楚的弄明白是怎樣實現了,查看下反編譯的代碼

這裏反編譯的代碼來自IDEA編譯後的target文件下自動反編譯的文件。
在這裏插入圖片描述
使用try-with-resource 的反編譯代碼如下

	@Test
    public void newCopyFile() {
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";

        try {
            FileInputStream fileInputStream = new FileInputStream(originalUrl);
            Throwable var4 = null;

            try {
                FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
                Throwable var6 = null;

                try {
                    int content;
                    try {
                        while((content = fileInputStream.read()) != -1) {
                            fileOutputStream.write(content);
                        }
                    } catch (Throwable var33) {
                        var6 = var33;
                        throw var33;
                    }
                } finally {
                    if (fileOutputStream != null) {
                        if (var6 != null) {
                            try {
                                fileOutputStream.close();
                            } catch (Throwable var32) {
                                var6.addSuppressed(var32);
                            }
                        } else {
                            fileOutputStream.close();
                        }
                    }

                }
            } catch (Throwable var35) {
                var4 = var35;
                throw var35;
            } finally {
                if (fileInputStream != null) {
                    if (var4 != null) {
                        try {
                            fileInputStream.close();
                        } catch (Throwable var31) {
                            var4.addSuppressed(var31);
                        }
                    } else {
                        fileInputStream.close();
                    }
                }

            }
        } catch (FileNotFoundException var37) {
            var37.printStackTrace();
        } catch (IOException var38) {
            var38.printStackTrace();
        }

    }

可以很容易的發現,編譯器將try-with-resource格式的代碼編譯成了嵌套的try-catch-finally的形式,所以可以證明try-with-resource能實現自動添加資源釋放

使用注意點:

  • 資源需要實現AutoCloseable接口
    在這裏插入圖片描述在這裏插入圖片描述
  • 資源對象被return的情況下,由調用方關閉
  • ByteArrayInputStream等不需要檢查關閉資源對象
  • 使用socket獲取的InputStream和OutputStream對象不需要關閉
    (如果直接關閉會關閉socket整個連接,需要調用socket的方法進行關閉-shutdowInput 和 shutdownOutput)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章