首頁>Club>
14
回覆列表
  • 1 # 技術呆東

    以io流處理為例,當我們在進行io流處理資料的時候,在最後需要把我們的流資源釋放掉,一般都是在finally語句後面,進行手動關閉,來保證資源關閉。但是在java7之後新加一個功能,我們只要把需要進行關閉資源的語句放在try()裡面,可以省去我們進行手動關閉,程式碼看上去也會更加簡潔

  • 2 # 瑁子

    1. 為什麼要手動關閉Java資源物件?

    首先:解釋Java的資源物件,它主要包括IO物件,資料庫連線物件。比如常見的InputStream、OutputStream、Reader、Writer、Connection、Statement、ResultSet、Socket等等,先程式碼列舉一個示例:

    FileInputStream f = new FileInputStream("sample.txt");

    f.close();//f物件即需要手動關閉的資源物件

    上述程式碼中f物件即需要手動關閉的資源物件。

    其次:如果類似的資源物件沒有及時的手動關閉,這個物件就會一直佔據記憶體,當這樣的物件越來越多,那記憶體被佔用的就會越來越多,久而久之就可能造成OutOfMemory,俗稱記憶體溢位。

    這時應該有人會問,Java不是有自己的垃圾回收機制GC麼?不是可以自動回收麼?

    這個問題問的好,我也一度非常困惑。

    第一:首先我們先了解一下GC的原理:

    在Java中,當沒有物件引用指向原先分配給某個物件的記憶體時,該記憶體便成為垃圾。JVM的一個系統級執行緒會自動釋放該記憶體塊。垃圾回收意味著程式不再需要的物件是"無用資訊",這些資訊將被丟棄。當一個物件不再被引用的時候,記憶體回收它佔領的空間,以便空間被後來的新物件使用。

    首先:GC只能回收記憶體。至於各種stream之類,他們下邊一般還開啟了各種其他的系統資源,比如檔案,比如輸入輸出裝置(鍵盤/螢幕等),等等。而這些裝置第一是不能自動關閉(因為誰知道你程式要用它到什麼時候啊),另一個系統內數量有限(比如鍵盤/螢幕同一時間只有一個)。最後,檔案和資料庫連線之類的東西還存在讀寫鎖定的問題。這些都導致使用者必須手動處理這些資源的開啟和關閉。

    其次為了“避免”程式設計師忘了自己釋放那些資源,Java提供了finalizer、PhantomReference之類的機制來讓程式設計師向GC註冊“自動回撥釋放資源”的功能。但GC回撥它們的時機不確定,所以只應該作為最後手段來使用,主要手段還是自己關閉最好。

    PS:關於GC其實有很多的知識可以深度挖掘,比如各種回收演算法,finalize()方法等等,大家感興趣的話可以自行搜尋研究,我就不班門弄斧了。

    2. 怎樣正確的手動關閉Java資源物件?

    先說一種最常見的關閉方式,在finally中進行關閉:

    FileInputStream f;

    try{

    f= new FileInputStream("sample.txt");

    //something that uses f and sometimes throws an exception

    }

    catch(IOException ex){

    /* Handle it somehow */

    }

    finally{

    f.close();

    }

    這裡在finally中進行資源物件關閉屬於Best Practice。因為即使物件f在使用的過程中出現異常,也能保證程式不會跳過後續的關閉操作。

    特別注意,自從Java1.7開始,支援了try-with-resources寫法,即將資源物件宣告的過程放在try()的括號裡面,這樣java在資源物件使用完成之後會自動關閉。

    try (

    FileOutputStream fileOutputStream = new FileOutputStream("E:\\A.txt");

    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

    DataOutputStream out = new DataOutputStream(bufferedOutputStream)

    )

    {

    out.write(data1);

    } catch (Exception e) {

    // TODO: handle exception

    }

    另外還有一些第三方庫提供了一些統一的關閉處理方法,例如

    import org.apache.commons.io.IOUtils;

    public static void main(String[] args) throws Exception{

    FileOutputStream fileOutputStream = null;

    BufferedOutputStream bufferedOutputStream=null;

    DataOutputStream out=null;

    byte[] data1 = "這個例子測試檔案寫".getBytes("GB2312");

    try {

    fileOutputStream = new FileOutputStream("E:\\A.txt");

    bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

    out = new DataOutputStream(bufferedOutputStream);

    out.write(data1);

    } catch (Exception e) {

    // TODO: handle exception

    } finally {

    IOUtils.closeQuietly(out);

    }

    }

    這個apache提供的IOUtils類庫可以透過IOUtils.closeQuietly(e)的形式關閉資源物件,實際內部實現依然是呼叫.close()方法。內部實現程式碼如下:

    public static void closeQuietly(final Closeable closeable) {

    try {

    if (closeable != null) {

    closeable.close();

    }

    } catch (final IOException ioe) {

    // ignore

    }

    }

  • 3 # 創域百家

    Java 7新增機制——自動關閉資源的try語句

    1 自動關閉資源介紹

    Java 7增強了try語句的功能——它允許在try關鍵字後跟一對圓括號,圓括號可以宣告,初始化一個或多個資源,此處的資源指得是那些必須在程式結束時必須關閉的資源(比如資料庫連線,網路連線等),try語句在該語句結束時自動關閉這些資源。

    為了保證try語句可以正常關閉資源,這些資源實現類必須實現Closeable或AutoCloseable介面,實現這些類就必須實現close方法。

    2 程式碼示例

    import java.io.*;

    public class AutoCloseTest

    {

    public static void main(String[] args)

    throws IOException

    {

    try (

    // 宣告、初始化兩個可關閉的資源

    // try語句會自動關閉這兩個資源。

    BufferedReader br = new BufferedReader(

    new FileReader("AutoCloseTest.java"));

    PrintStream ps = new PrintStream(new

    FileOutputStream("a.txt")))

    {

    // 使用兩個資源

    System.out.println(br.readLine());

    ps.println("莊生曉夢迷蝴蝶");

    }

    }

    }

    3 執行結果

    E:\test\Java\Java8\ExceptionTEST\src>java AutoCloseTest

    import java.io.*;

    檔案a.txt中生成

    莊生曉夢迷蝴蝶

    4 結果分析

    try後的小括號分別宣告,初始化兩個IO流,由於BufferedReader,PrintStream都實現了Closeable介面,而且它們放在try語句中宣告和初始化,所有try語法會自動關閉它們。因此上面的程式碼是安全的。

  • 中秋節和大豐收的關聯?
  • 自己天天看到有爭論手機拍照永遠比不上單反的,有意思嗎?你們覺得呢?