2013-04-23 16 views
20

我,如果下面的代碼在關閉的InputStream finally塊正確在finally塊中靜默關閉InputStream而不丟失原始異常的正確方法是什麼?

InputStream is = new FileInputStream("test"); 
try { 
    for(;;) { 
     int b = is.read(); 
     ... 
    } 
} finally { 
    try { 
     is.close(); 
    } catch(IOException e) { 
    } 
} 

如果is.read期間發生異常時想()將它忽略/抑制如果is.close期間發生異常()?

+0

與IOUtils關閉你不能捕獲該異常之前的最後處理呢? – 2013-04-23 08:04:48

+1

在https://code.google.com/p/guava-libraries/wiki/ClosingResourcesExplained和https://code.google.com/p/guava-libraries/issues/detail?id上查看以下兩個鏈接= 1118和 – artfullyContrived 2013-04-23 08:51:03

回答

1

is.close()的異常將被抑制,is.read()中的異常將傳播。

+0

是的,但只有當來自'is.close()'的異常是一個IO異常。 – 2013-04-23 09:03:48

+0

通常它是一個NullpointerException,當鏈接流時,第一個流拋出FileNotFpundException – AlexWien 2013-04-23 09:53:07

+0

@Alex在給出的例子中,在is.close調用時'is'不能爲null,否則FileInputStream的構造函數會拋出像你之前說過的例外。但是,這不在異常塊中。我只能回覆代碼,因爲它顯示的不是代碼,因爲我們會自己寫! @Etienne你是對的,在這個例子中他們都拋出同樣的異常。 – monkjack 2013-04-23 15:14:40

1

根據您的代碼示例,如果在int b = is.read();點發生異常,則異常將在呼叫鏈上升高。

注意雖然finally塊仍然會執行,如果Inputstream無效另一個異常將被拋出,但這個異常將被「吞噬」,這可能是可以接受的,這取決於您的使用情況。

編輯:

根據您的問題的標題,我想補充一點,你有什麼是我認爲很好。您可能需要額外添加一個catch塊來顯式處理(或可能包裝)第一個try塊中的任何異常,但也可以讓任何IO異常提升 - 這實際上取決於您的API。 IO異常升高可能會也可能不會被接受。如果是,那麼你有什麼好 - 如果不是那麼你可能想要處理/包裝IO例外更適合您的程序。

+0

該異常不會被吞下,它將被傳播,而不是原來的異常。 – flup 2013-04-23 08:51:17

+0

如果'InputStream'爲'null',那麼代碼將產生一個隱藏原始異常的NPE,但是如果'close()'產生一個IO異常,那麼這個異常將被丟棄,並且原始異常將會傳播。 – 2013-04-23 09:01:48

+0

@EtienneMiret同意了,它會的。但答案表明,NPE會被吞嚥,而不會。 – flup 2013-04-23 09:05:29

14

最好的方法是使用Java 7並使用資源嘗試,或者做同樣的事情manualy並添加異常從關閉作爲抑制異常。

Pre Java 7: 如果你正在拋出你的自定義異常,你可以像它在Java 7中那樣添加它的異常異常(在你的異常創建字段中List抑制,您的例外,看看有太多 如果你不能做到這一點,我不知道什麼更好的不僅僅是記錄它

例子:。 從Java tutorials

static String readFirstLineFromFile(String path) throws IOException { 
    try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
     return br.readLine(); 
    } 
} 

,但更好的形式是:

static String readFirstLineFromFile(String path) throws IOException { 
    try (FileReader fr = new FileReader(path); 
     BufferedReader br = new BufferedReader(fr)) { 
     return br.readLine(); 
    } 
} 

這樣即使的FileReader的創作是succesfull但BufferedReader類的創建失敗(例如沒有足夠的內存),的FileReader將被關閉。

+1

我不明白,代碼示例java7? – AlexWien 2013-04-23 08:13:46

+1

你能提供一些示例代碼來解釋你的意思嗎? – 2013-04-23 09:28:07

6

Java 6 specs

如果try塊執行突然完成任何其他原因R,則執行最終塊。然後有一個選擇: 如果finally塊正常完成,那麼由於原因R,try語句突然完成。 如果finally塊由於原因S而突然完成,則對於原因S,try語句突然完成(並且理由R被丟棄)。

所以你是對的,你將失去原來的例外。

解決方案可能是編寫你的finally塊,以便防禦性地進行,如果finally塊失敗,比try catch塊發生異常,這是一個更大的驚喜(值得宣傳)。

因此,舉例來說,如果可能的話,當你試圖關閉它的流可能爲空,檢查:

InputStream is = new FileInputStream("test"); 
try { 
    for(;;) { 
     int b = is.read(); 
     ... 
    } 
} finally { 
    try { 
     if(is!=null) { 
      is.close(); 
     } 
    } catch(IOException e) { 
    } 
} 

在Java 7,Alpedar的解決方案是去當然的方式。

+0

is = null是不可能的,新的FileInputStream(「test」)不能返回null – 2013-04-23 15:08:33

+0

它是一個簡單的例子,它取決於'...'中發生了什麼。正在尋找一個可能會在finally塊中拋出的運行時異常,因爲當事情變得有趣的時候。 – flup 2013-04-23 17:51:46

2

隨着你發佈的代碼:

  • 如果is.close()拋出IOException,它就會被丟棄,原來的異常傳播。
  • 如果is.close()拋出別的東西(一個RuntimeException或一個Error),它會傳播並丟棄原始異常。

使用Java 7,關閉一個InputStream不會丟失原始異常的正確方法是使用一個try-with-resources statement

try (InputStream is = new FileInputStream("test")) { 
    for(;;) { 
     int b = is.read(); 
     // ... 
    } 
} 

此前的Java 7,你做什麼就好了,除了你可能想要捕獲所有異常,而不僅僅是IOException s。

0

如何對未來的解決方案:

InputStream is = new FileInputStream("test"); 
Exception foundException=null; 
try { 
    for(;;) { 
     int b = is.read(); 
     ... 
    } 
} catch (Exception e){ 
    foundException=e; 
} 
finally { 
    if(is!=null) 
    try { 
     is.close(); 
    } catch(IOException e) { 
    } 
} 
//handle foundException here if needed 
0

如果is.read期間發生異常時()將它忽略/抑制如果is.close期間發生異常()?

是的。你在close()中有一個catch塊,它不會重新拋出異常。它不會被傳播或重新生成。

+0

try {throw new IllegalArgumentException(); } finally {try {throw new IllegalStateException();} catch(Exception e2){}} - 引發IllegalArgumentException – 2013-04-23 11:02:13

+0

@EvgeniyDorofeev你到底在說什麼? – EJP 2013-04-24 10:27:51

0

這是幫助理解您的問題的示例, 如果您在try-catch塊中聲明掃描器,它將給編譯器警告資源未關閉。 所以要麼使它在本地或只是嘗試()

import java.util.InputMismatchException; 
import java.util.Scanner; 

class ScanInt { 
public static void main(String[] args) { 
    System.out.println("Type an integer in the console: "); 

    try (Scanner consoleScanner = new Scanner(System.in);) { 
     System.out.println("You typed the integer value: " 
       + consoleScanner.nextInt()); 

    } catch (InputMismatchException | ArrayIndexOutOfBoundsException exception) { 
     System.out.println("Catch Bowled"); 
     exception.printStackTrace(); 

    } 
    System.out.println("----------------"); 
} 
} 
5

您可以從https://commons.apache.org/proper/commons-io/

public void readStream(InputStream ins) { 

    try { 
     //do some operation with stream   
    } catch (Exception ex) { 
     ex.printStackTrace();   
    } finally { 
     IOUtils.closeQuietly(ins); 
    }  
} 
+0

請勿在IOUtils 2.6中使用,棄用和移除,而不用更換。 「請使用try-with-resources語句或手動處理抑制的異常。」 – Sergio 2018-02-12 15:31:24

相關問題