31

以下のコードがfinallyブロックでInputStreamを正しく閉じるかどうか疑問に思っています

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

is.read() 中に例外が発生した場合、is.close() 中に例外が発生した場合、無視/抑制されますか?

4

9 に答える 9

17

最善の方法は、Java 7 を使用してリソースで try を使用するか、手動で同じことを行い、抑制された例外としてクローズからの例外を追加することです。

Java 7より前:カスタム例外をスローしている場合、Java 7で行われているように、抑制された例外を追加できます(例外でフィールドを作成し、抑制されたリストを作成し、クローズ操作からの例外をそこに置き、例外を処理するときにそこを見てくださいそれができない場合は、ログに記録する以外に方法はありません。

例: Java チュートリアルから

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 の作成に成功しても BufferedReader の作成に失敗した場合 (メモリ不足など)、FileReader は閉じられます。

于 2013-04-23T08:07:57.593 に答える
14

https://commons.apache.org/proper/commons-io/の IOUtils で閉じることができます

public void readStream(InputStream ins) {
    try {
        //do some operation with stream         
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        IOUtils.closeQuietly(ins);
    }
}
于 2015-12-23T07:25:04.787 に答える
7

Java 6仕様は言う

try ブロックの実行が R 以外の理由で突然終了した場合、finally ブロックが実行されます。次に選択肢があります。finally ブロックが正常に完了した場合、try ステートメントは理由 R のために突然完了します。finally ブロックが理由 S のために突然完了した場合、try ステートメントは理由 S のために突然完了します (そして理由 R は破棄されます)。

そうです、元の例外が失われます。

解決策はおそらく、try catch ブロックから例外が発生した場合よりも、finally ブロックが失敗した場合の方が大きな驚き (伝播する価値がある) になるように、finally ブロックを非常に防御的に記述することです。

したがって、たとえば、ストリームを閉じようとしたときにストリームが null である可能性がある場合は、次のように確認してください。

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

もちろん、Java 7 では、Alpedar のソリューションが有効です。

于 2013-04-23T08:50:29.330 に答える
3

is.close() からの例外は抑制され、is.read() からの例外が伝搬されます。

于 2013-04-23T08:04:56.413 に答える
2

あなたが投稿したコードで:

  • is.close()がスローされた場合IOException、それは破棄され、元の例外が伝播します。
  • is.close()が何か他のもの ( aRuntimeExceptionまたは an ) をスローした場合Error、それは伝播し、元の例外は破棄されます。

Java 7 では、元の例外を失うことなく InputStream を閉じる正しい方法は、try-with-resources ステートメントを使用することです。

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

Java 7 より前では、s だけでなくすべての例外をキャッチしたい場合を除いて、何をしても問題ありませんIOException

于 2013-04-23T09:37:19.670 に答える
1

ポイントで例外が発生した場合のコードサンプルに基づいて、int b = is.read();例外はコールチェーンの上位に発生します。

ただし、finally ブロックは引き続き実行され、Inputstream無効な場合は別の例外がスローされますが、この例外は「飲み込まれ」、ユースケースによっては許容される場合があることに注意してください。

編集:

あなたの質問のタイトルに基づいて、あなたが持っているものは私の意見では問題ないと付け加えます。catch最初のブロック内で例外を明示的に処理 (またはおそらくラップ) するブロックを追加することもできますがtry、IO 例外を発生させることも許容されます - これは本当に API に依存します。IO 例外を発生させることが許容される場合と許容されない場合があります。そうである場合は、問題ありません。そうでない場合は、プログラムにより適したもので IO 例外を処理/ラップすることをお勧めします。

于 2013-04-23T08:05:32.873 に答える
0

is.read() 中に例外が発生した場合、is.close() 中に例外が発生した場合、無視/抑制されますか?

はい。例外を再スローしない close() の例外の catch ブロックがあります。したがって、伝播も再スローもされません。

于 2013-04-23T10:56:02.780 に答える