1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        每日一例 | 更優(yōu)雅地關(guān)閉流(Stream)

        共 6863字,需瀏覽 14分鐘

         ·

        2021-05-09 20:25

        在日常開發(fā)中,我們會經(jīng)常用到流(Stream),比如InputStream/OutPutStreamFileInputStream/FileOutPutStream等,你是不是經(jīng)常像下面展示的這樣手動關(guān)閉流,或者甚至都不關(guān)閉流呢?今天我們就來探討下關(guān)于流關(guān)閉的問題。

        通常的關(guān)閉方式

        我們先看一段代碼:

         /**
             * 讀取文件
             */

        private static void readFile() {
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream("target/classes/test.txt");
                byte[] bytes = new byte[1024];
                // 讀取文件
                while (fileInputStream.read(bytes) != -1) {
                    System.out.println(new String(bytes));
                }
                System.out.println(1/0);
                System.out.println(fileInputStream.available());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // 關(guān)閉資源
                if (Objects.nonNull(fileInputStream)) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("結(jié)束");
        }

        不符合代碼質(zhì)量規(guī)范

        上面這段代碼,從邏輯上將是ok的,但是從代碼質(zhì)量的角度來說是不合格的,如果你用sonar或者sonarLint插件掃描你的項目的話,它會提示你存在Code smell,也就是合理的寫法:

        提示信息的意思是,你應(yīng)該把第24行的代碼改成try-with-resources的形式。這里簡單補(bǔ)充一下,try-with-resoucesJDK1.7引入的,目的是優(yōu)化資源關(guān)閉問題,將之前try-catch-finally優(yōu)化成try-catch,之前你需要手動在finally中關(guān)閉,通過try-with-resouces的方式,你再也不用手動關(guān)閉你的各種流了。

        try-with-resources方式

        上面的代碼優(yōu)化后,是這樣的:

        private static void readFile2() {
            try (FileInputStream fileInputStream = new FileInputStream("target/classes/test.txt")) {
                byte[] bytes = new byte[1024];
                // 讀取文件
                while (fileInputStream.read(bytes) != -1) {
                    System.out.println(new String(bytes));
                }
                 throw new FileNotFoundException("");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        區(qū)別

        相比之前代碼更簡潔,唯一的區(qū)別是:

        try (FileInputStream fileInputStream = new FileInputStream("target/classes/test.txt")) {

        就是將你需要在try代碼塊中用到的資源,都放進(jìn)try()中,這樣你的資源就會自動被關(guān)閉。這種方式其實(shí)就是一種語法糖(對用戶更更友好),從代碼底層來說和前面手動關(guān)閉的方式區(qū)別不大,只是之前由你寫關(guān)閉,現(xiàn)在jdk在編譯的時候,會自己加,下面反編譯的代碼,很好地說明了這一點(diǎn):

        private static void readFile2() {
            try {
              FileInputStream fileInputStream = new FileInputStream("target/classes/test.txt");
              Throwable throwable = null;
              try {
                byte[] bytes = new byte[1024];
                while (fileInputStream.read(bytes) != -1)
                  System.out.println(new String(bytes)); 
                throw new FileNotFoundException("");
              } catch (Throwable throwable1) {
                throwable = throwable1 = null;
                throw throwable1;
              } finally {
                if (throwable != null) {
                  try {
                    fileInputStream.close();
                  } catch (Throwable throwable1) {
                    throwable.addSuppressed(throwable1);
                  } 
                } else {
                  fileInputStream.close();
                } 
              } 
            } catch (FileNotFoundException e) {
              e.printStackTrace();
            } catch (IOException e) {
              e.printStackTrace();
            } 
          }

        發(fā)現(xiàn)新大陸

        本來事情到這里應(yīng)該結(jié)束了,但是我為了搞清楚本質(zhì)區(qū)別,我在close()方法上打了斷點(diǎn),我想看下是不是我不關(guān)閉流,它就不自己關(guān)閉。

        我先試了try-with-resouces的方式,close方法被調(diào)用,這是OK的;我又試了第一段的傳統(tǒng)寫法,close也被調(diào)用了。

        但是我發(fā)現(xiàn),close方法都被調(diào)用了兩次,而且在第一段傳統(tǒng)寫法那里,是先調(diào)了close方法,然后再進(jìn)入finally執(zhí)行關(guān)閉。我已經(jīng)有點(diǎn)困惑了,但我還是想再看下不手動關(guān)閉的情況,這次比前兩次更神奇,close方法竟然也被調(diào)用了,太神奇了吧!

        我還在想,JDK什么時候有這個新特性的,不竟然不知道,難道和我用JDK9有關(guān),但查了資料,發(fā)現(xiàn)jdk9只是支持在try-with-resources中使用final修飾的變量,也沒有這個呀,這時候我看了FileInputStream的源碼,發(fā)現(xiàn)在FileInputStream的構(gòu)造方法中,這樣幾行代碼:

         fd = new FileDescriptor();
         fd.attach(this);

        也就是在創(chuàng)建流的時候,會把當(dāng)前流加入到FileDescriptor中,FileDescriptor有一個closeAll方法,會循環(huán)關(guān)閉加入其中的流,但是這個方法也只有在FileInputStreamclose中調(diào)用呀。

        我還覺得是不是正常情況下會自動關(guān)閉,但是異常情況下不會關(guān)閉,但是試了異常情況下也會走到close方法,我裂了,難道是360替我關(guān)閉了?

        這個問題我得再好好研究下,今天就到這里吧,溫馨提示,假期余額不足

        以下內(nèi)容來源網(wǎng)絡(luò),侵刪

        - END -


        瀏覽 45
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            尻逼久久 | 亚洲国产成人视频 | 91久久香蕉国产日韩欧美9色 | 99re这里只有 | 亚色视频在线 | 九九九精品视频免费观看 | 男女超爽视频免费播放 | 人妻精品在线 | 在线超鹏牛| 逼逼精品 |