1. 程式人生 > >連環清潔工之特殊任務--java資源如何關閉?

連環清潔工之特殊任務--java資源如何關閉?

小C是一名特殊的黑客,他專門為黑客提供服務,掃除黑客攻擊的痕跡,避免被查到為何人攻擊。

 

今天他正興致勃勃的玩遊戲《連環清潔工》,連環清潔工是由iFun4all S.A.製作發行的一款犯罪題材動作冒險類遊戲,故事劇情講述的是一個專門山寨別人的殺手,專門模仿最近發生的大案要案,製造類似的凶殺案。遊戲中玩家扮演一名專業凶案現場清掃人員,為客戶處理屍體、清理血跡、隱藏凶器等犯罪證據,玩家接受任務的時候不能問任何問題。

突然接到小白請求幫助的緊急電話,注:小白是小C入侵小白的電腦後認識的,詳情太多,參見詳細地址https://cloud.tencent.com/developer/news/333203。

原來小白在學習java,碰到一個程式設計問題:檔案操作關閉資源的時候會莫名其妙的報錯。程式碼如下:

 public void openFile() throws IOException {
 FileReader reader = new FileReader("someFile");
 int i=0;
 while(i != -1){
 i = reader.read();
 System.out.println((char) i );
 }
 reader.close();
 System.out.println("--- File End ---");
 }

小C針對小白剛剛程式設計的經歷,採用循循誘導的方式。

小C:上面的程式碼是不是沒有捕獲異常?是不是可以把異常捕獲到,再分析異常原因?

小白:對哦,那我使用try 。。catch試試

 public void openFile(){
 try {
 // constructor may throw FileNotFoundException
 FileReader reader = new FileReader("someFile");
 int i=0;
 while(i != -1){
 //reader.read() may throw IOException
 i = reader.read();
 System.out.println((char) i );
 }
 reader.close();
 System.out.println("--- File End ---");
 } catch (FileNotFoundException e) {
 //do something clever with the exception
 } catch (IOException e) {
 //do something clever with the exception
 }
 }

小C:做的很不錯,知道捕捉多重異常了!,資源的關閉是不是放到finally比較好?

小白:對哦,我看語法有這樣的,那我重新寫一下

    public void openFile() throws IOException {
        FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        }  catch (FileNotFoundException e) {
            //do something clever with the exception
        } catch (IOException e) {
            //do something clever with the exception
        }finally {
            reader.close();
            System.out.println("--- File End ---");
        }
    }

小白:哦,還忘掉reader的判斷,再改一下:

    public void openFile() throws IOException {
        FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        }  catch (FileNotFoundException e) {
            //do something clever with the exception
        } catch (IOException e) {
            //do something clever with the exception
        }finally {
            if(reader != null){
                reader.close();
            }
            reader.close();
            System.out.println("--- File End ---");
        }
    }

 

小C:reader的關閉,是不是還有可能丟擲異常,是不是還要捕獲?

小白:是哦,我忘記了,修改後的是這樣的嗎?

    public void openFile() throws IOException {
        FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        }  catch (FileNotFoundException e) {
            //do something clever with the exception
        } catch (IOException e) {
            //do something clever with the exception
        }finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    //do something clever with the exception
                }
            }
            reader.close();
            System.out.println("--- File End ---");
        }
    }

小C:程式碼是不是太繁瑣了?有沒有更簡潔的辦法?讓jvm幫你處理一些繁瑣的工作?

小白:聽說過ry-with-resources,但沒有用過。

小C:那你看看這個是否簡潔了一些呢?

    public void openFile() throws IOException {
        try (FileReader reader = new FileReader("someFile")){
            ;
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        }  catch (FileNotFoundException e) {
            //do something clever with the exception
        } catch (IOException e) {
            //do something clever with the exception
        }
    }

把資源放到try()內部, JVM會呼叫java.lang.AutoCloseable.close() 方法,自動關閉try()內部的資源。

小白:厲害,我學會了。

小C:那我考考你。

    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
            return;
            } finally {
            System.out.println("Goodbye world");
            }
    }
    

這個會打印出什麼結果?

小白:“hello world” 因為return 退出了,finally不能執行。

小C:不對,finally總是會執行的,列印

Hello world

Goodbye world

小白:我明白了,finally總是會執行的。

小C:那可不一定哦,看看這個:

    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
            System.exit(0);
            } finally {
            System.out.println("Goodbye world");
            }
    }

小白:不是列印?

Hello world

Goodbye world

小C:不論try語句塊的執行是正常地還是意外地結束,finally語句塊確實都會執行。

然而在這個程式中,try 語句塊根本就沒有結束其執行過程。System.exit 方法

將停止當前執行緒和所有其他當場死亡的執行緒。finally 子句的出現並不能給予線

程繼續去執行的特殊許可權。

如果想要執行,想要使用hook

    public static void main(String[] args) {
        System.out.println("Hello world");
        Runtime.getRuntime().addShutdownHook(
        new Thread() {
        public void run() {
        System.out.println("Goodbye world");
        }
        });
        System.exit(0);
        }

小白:好神奇!

小C:學無止境,一起加油!今天到這裡了,我還要繼續我的遊戲呢。

參考資料

【1】http://tutorials.jenkov.com/java-exception-handling/basic-try-catch-finally.html

【2】https://howtodoinjava.com/java/exception-handling/try-catch-finally/

【3】https://howtodoinjava.com/java7/try-with-resources/

【4】java