你還在使用 try-catch-finally 關閉資源?

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

代碼一定得寫的優雅一點!
你還在使用try-catch-finally關閉資源嗎,如果是,那麼就有點out了。皮皮甜手把手教你使用JDK7引用的try-with-resource
JDK7之前資源的關閉姿勢:

/**
 * jdk7以前關閉流的方式
 *
 * @author hetiantian
 * */
public class CloseResourceBefore7 {
    private static final String FileName = "file.txt";

    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = null;

        try {
            inputStream = new FileInputStream(FileName);
            char c1 = (char) inputStream.read();
            System.out.println("c1=" + c1);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }
}

JDK7及以後關閉資源的正確姿勢
try-with-resource Resource的定義:
所有實現了 java.lang.AutoCloseable[1] 接口(其中,它包括實現了 java.io.Closeable[2] 的所有對象),可以使用作爲資源。簡單Demo進行證實:實現java.lang.AutoCloseable接口的Resource類.

/**
 * 資源類
 *
 * @author hetiantian
 * */
public class Resource implements AutoCloseable {
    public void sayHello() {
        System.out.println("hello");
    }

    @Override
    public void close() throws Exception {
        System.out.println("Resource is closed");
    }
}

測試類CloseResourceIn7.java

/**
 * jdk7及以後關閉流的方式
 *
 * @author hetiantian
 * */
public class CloseResourceIn7 {
    public static void main(String[] args) {
        try(Resource resource = new Resource()) {
            resource.sayHello();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

打印結果:

hello
Resource is closed

當存在多個打開資源的時候:資源二Resource2.java

/**
 * 資源2
 *
 * @author hetiantian
 * */
public class Resource2 implements AutoCloseable {
    public void sayhello() {
        System.out.println("Resource say hello");
    }

    @Override
    public void close() throws Exception {
        System.out.println("Resource2 is closed");
    }
}

測試類CloseResourceIn7.java

/**
 * jdk7及以後關閉流的方式
 *
 * @author hetiantian
 * */
public class CloseResourceIn7 {
    public static void main(String[] args) {
        try(Resource resource = new Resource(); Resource2 resource2 = new Resource2()) {
            resource.sayHello();
            resource2.sayhello();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

打印結果:

hello
Resource say hello
Resource2 is closed
Resource is closed

即使資源很多,代碼也可以寫的很簡潔,如果用JDK7之前的方式去關閉資源,那麼資源越多,用fianl關閉資源時嵌套也就越多。

那麼它的底層原理又是怎樣的呢,由皮皮甜獨家揭祕優雅關閉資源背後的密碼祕密
查看編譯的class文件CloseResourceIn7.class:

public class CloseResourceIn7 {
    public CloseResourceIn7() {
    }

    public static void main(String[] args) {
        try {
            Resource resource = new Resource();
            Throwable var2 = null;

            try {
                resource.sayHello();
            } catch (Throwable var12) {
                var2 = var12;
                throw var12;
            } finally {
                if (resource != null) {
                    if (var2 != null) {
                        try {
                            resource.close();
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);
                        }
                    } else {
                        resource.close();
                    }
                }

            }
        } catch (Exception var14) {
            var14.printStackTrace();
        }

    }
}

可以發現編譯以後生成了try-catch-finally語句塊 finally中的var2.addSuppressed(var11);
是不是有疑問?其實這麼做是爲了處理異常屏蔽的,我們將代碼修改一下。
資源Resource.java

/**
 * 資源類
 *
 * @author hetiantian
 * */
public class Resource implements AutoCloseable {
    public void sayHello() throws Exception {
        throw new Exception("Resource throw Exception");
    }

    @Override
    public void close() throws Exception {
        throw new Exception("Close method throw Exception");
    }
}

兩個方法裏面都拋出異常
測試類CloseResourceIn7.java

/**
 * jdk7及以後關閉流的方式
 *
 * @author hetiantian
 * */
public class CloseResourceIn7 {

    public static void main(String[] args) {
        try {
            errorTest();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void errorTest() throws Exception {
        Resource resource = null;
        try {
            resource = new Resource();
            resource.sayHello();
        }

        finally {
            if (resource != null) {
                resource.close();
            }
        }
    }
}

打印結果:

java.lang.Exception: Close method throw Exception
    at com.shuwen.Resource.close(Resource.java:15)
    at com.shuwen.CloseResourceIn7.errorTest(CloseResourceIn7.java:27)
    at com.shuwen.CloseResourceIn7.main(CloseResourceIn7.java:12)

只打印了最後出現的異常【異常屏蔽】這樣會給開發人員排查錯誤帶來一定的困難 我們換成try-with-resource方法實現CloseResourceIn7.java

/**
 * jdk7及以後關閉流的方式
 *
 * @author hetiantian
 * */
public class CloseResourceIn7 {

    public static void main(String[] args) {
        try {
            errorTest();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void errorTest() throws Exception {
        try(Resource resource = new Resource()) {
            resource.sayHello();
        }

    }
}

打印信息:

java.lang.Exception: Resource throw Exception
    at com.shuwen.Resource.sayHello(Resource.java:10)
    at com.shuwen.CloseResourceIn7.errorTest(CloseResourceIn7.java:20)
    at com.shuwen.CloseResourceIn7.main(CloseResourceIn7.java:12)
    Suppressed: java.lang.Exception: Close method throw Exception
        at com.shuwen.Resource.close(Resource.java:15)
        at com.shuwen.CloseResourceIn7.errorTest(CloseResourceIn7.java:21)
        ... 1 more

可以發現,異常信息中多了一個Suppressed的提示,告訴我們這個異常其實由兩個異常組成,Close method throw Exception這個異常是被Suppressed【屏蔽】的異常
怎麼樣,是不是很簡單呢,如果學會了話來個在看吧!

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/zhibo

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-07-01
本文作者:何甜甜在嗎
本文來自:“互聯網架構師 微信公衆號 ”,瞭解相關信息可以關注“[互聯網架構師](https://mp.weixin.qq.com/s/BW5teWqDwJe372A-RT_VeQ

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章