2016-06-07 34 views
20

當在構造函數中打開InputStream,然後將其傳遞給超級構造函數時,是否有任何使用try-with-resources的好方法?嘗試與資源時調用超級構造函數

基本上就是我想要做的是這樣的:

public class A { 
    public A(InputStream stream) { 
     // Do something with the stream but don't close it since we didn't open it 
    } 
} 

public class B { 
    public B(File file) { 
     // We open the stream so we need to ensure it's properly closed 
     try (FileInputStream stream = new FileInputStream(file)) { 
      super(new FileInputStream(file)); 
     } 
    } 
} 

但是,當然,因爲super必須在構造函數中的第一條語句,這是不允許的。有沒有什麼好的方法來實現這一目標?

+2

我希望調用者提供輸入流給'public B(InputStream in)'並關閉它。沒有理由讓派生類比基類更少用途。 – EJP

+0

功能更多,但使用起來也更麻煩。我可以支持這兩種,但不具有'B(文件文件)'構造函數不是一個選項。 – Raniz

+2

在我看來,你的問題來自消耗A的構造函數內的流。如果不是這種情況,您只需將該流存儲在一個實例變量中並設置「AutoClosable」。 –

回答

25

考慮使用靜態工廠方法,而不是直接使用構造函數。使至少B的構造私人,並創建一個方法,如

private B(InputStream is) { 
    super(is); 
    // Whatever else is needed 
} 

public static B newInstance(File file) { 
    B result; 
    try (FileInputStream stream = new FileInputStream(file)) { 
     result = new B(stream); 
    } 
    // Further processing 
    return result; 
} 
+0

是啊,這似乎是要走的路 – Raniz

2

另一種方式去:

public class A { 
    protected A(){ 
     // so he can't be called from the outside, subclass ensure that init is done properly. 
    } 

    public A(InputStream stream) { 
     init(stream); 
    } 
    // not be able to call it from outside 
    protected final init(InputStream is){ 
     //here goes the code 
    } 
} 

public class B { 
    public B(File file) { 
     // We open the stream so we need to ensure it's properly closed 
     try (FileInputStream stream = new FileInputStream(file)) { 
      init(stream); 
     } 
    } 
} 

我在這裏張貼這是一個可能的答案,但是我在這裏consdering:

  1. 可以更新的代碼
  2. 你正在移動的構造函數的代碼到init方法,由於受保護的空參數構造函數,只有子類必須正確處理對init的調用。有些人可能會認爲設計不太好。我的觀點是儘快對子類進行子類化,只有當你使用它時,你必須更多地瞭解它。
+0

正如你所說,它需要訪問* A *的源代碼,並且如果* A *中有最終變量需要從內容中初始化流。 – Raniz

+2

你應該使'init'' final',否則一個子類可以覆蓋它並破壞'A'的構造函數。我認爲這被稱爲構造泄漏或類似的東西。 – Oebele

+0

好點我加了它。 – Walfrat

-1

很遺憾,我手邊沒有編譯器來測試,但是你可以不這樣做,如下所示。

public class B { 
    private static InputStream file2stream(File f){ 
     // We open the stream so we need to ensure it's properly closed 
     try (FileInputStream stream = new FileInputStream(file)) { 
      return stream; 
     }catch(/*what you need to catch*/){ 
      //cleanup 
      // possibly throw runtime exception 
     } 
    } 
    public B(File file) { 
     super(file2stream(file)) 
    } 
} 
+3

不幸的是,在'file2stream'結束之前'try'塊的結束,在文件被傳遞到'super'之前關閉文件。 –

+0

我可能會錯過這個問題,但我認爲這是重點。我解釋了這樣一個問題,即試圖保護的唯一東西就是構建InputStream,如果不是這種情況怎麼理解呢? – lijat

+1

我想,你不明白漢克德的評論。問題是,在試用資源中,打開的資源(流)在塊的結尾處關閉。'return'語句並不妨礙這一點(或者對'try'沒有任何意義)。所以當'file2stream'返回資源時,它已經被**關閉了。還要注意* try-with-resources *(這是爲了關閉資源完成的)和* try-catch *之間的區別,這是爲了捕獲異常而完成的,而不是這裏討論的那個。 – RealSkeptic