web-dev-qa-db-ja.com

クローズJava InputStreams

Java InputStreamsを使用するときのclose()メソッドの使用法についていくつか質問があります。ほとんどの開発者が読んだり読んだものから、InputStreamに対してclose()を明示的に呼び出す必要があります。しかし、今日はJavaプロパティファイルの使用を検討していましたが、見つかったすべての例には次のようなものがあります。

Properties props = new Properties();
try {
    props.load(new FileInputStream("message.properties"));
    //omitted.
} catch (Exception ex) {}

上記の例では、InputStreamは使用後に到達できないため、close()を明示的に呼び出す方法はありません。ほとんどの人が明示的に閉じることについて言っていることと矛盾しているように見えますが、InputStreamの同様の使用法を多く見ました。 OracleのJavaDocを読みましたが、Properties.load()メソッドがInputStreamを閉じるかどうかは言及していません。これが一般的に受け入れられるのか、それとも次のようなことをするのが好ましいのかと思います。

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    try {
        fis.close();
    } catch (IOException ioex) {
        //omitted.
    }
}

どちらの方法がより良いおよび/またはより効率的ですか?それとも本当に重要ですか?

62
Jason Watkins

プロパティチュートリアル の例は、ロード後にFileInputStreamを明示的に閉じるため、loadメソッドが責任を負わないと想定しても安全だと思います。 。

// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();

参考のために、 Apache Harmony の実装 Properties を確認しました。notcloseロード時のストリーム。

25
Bill the Lizard

Propertiesクラスは、入力ストリームをLineReaderにラップして、プロパティファイルを読み取ります。入力ストリームを提供するので、それを閉じるのはあなたの責任です。

2番目の例は、ストリームをはるかにうまく処理する方法です。他の誰かに頼ってストリームを閉じないでください。

改善点の1つは、 IOUtils.closeQuietly() を使用することです

ストリームを閉じるために、例えば:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    IOUtils.closeQuietly(fis);
}
47
Jon

私はリソースを試してみました(少なくともJava 7+)の場合:

Properties props = new Properties();

try(InputStream fis = new FileInputStream("message.properties")) {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
}

Tryブロックが終了すると、close()呼び出しが自動的に呼び出されます。

30
Daniel Voina

ドキュメントでは、props.loadは入力ストリームを閉じます。提案したように、finallyブロックで入力ストリームを手動で閉じる必要があります。

関数がInputStreamを閉じるのは正常ではありません。ガベージコレクションされていない言語のメモリと同じ規則が適用されます。可能であれば、ストリームを開いた人がストリームを閉じる必要があります。そうでなければ、ストリームを開いたままにしておくのは非常に簡単です(関数はそれを閉じると思いますが、閉じない、または何か...)

13
Adrian Smith

Java 7+を使用している場合、これを使用できます。

try(InputStream is = new FileInputStream("message.properties")) {
    // ...
}
12
kwo2002

最初のコードサンプルは、最終的にFileInputStreamのfinalizeメソッドに依存してファイルを実際に閉じるように見えます。どちらの場合でもファイルが閉じられますが、2番目の例の方が良いと思います。

Byteストリームのようにcloseが何もせず省略できる場合があります。そうでない場合は、finallyブロックでファイルを明示的に閉じる方が良いと思います。開いたら、閉じます。

Oracleのサイトには Java Platform Performance という本があり、その付録でファイナライザーについて説明しています。

ほとんどの場合、ファイナライザに頼るのではなく、独自のクリーンアップを行う方が良いでしょう。ファイナライザを使用すると、不確定な期間回復されない重要なリソースが残る場合があります。重要なリソースを適時に解放するためにファイナライザーを使用することを検討している場合は、再検討することをお勧めします。

7
Nathan Hughes

他の人の答えに少し加えてみましょう。

Apache Commons IO をインポートできる場合、非常に便利な AutoCloseInputStream sクラスを使用できます:InputStreamをラップし、ラップされたインスタンスを使用するだけで、入力の終わりに到達するか、ストリームが明示的に閉じられるかのいずれか早い方で、自動的に閉じられます。

2
Unai Vivi