36

さて、私は次のことを行っています(変数名は変更されています):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

最近、FindBugs を使い始めました。これは、ストリームを適切に閉じていないことを示唆しています。私は、finally{} ブロックで何かできることがあるかどうかを確認することにしました。すると、そうそう、close() が IOException をスローできることがわかりました。人々はここで何をすべきですか?Java ライブラリがスローするチェック例外が多すぎます。

4

9 に答える 9

47

Java 7以降の場合は、try-with-resourcesを使用する必要があります。

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Java6以下で立ち往生している場合...

このパターンは、 nullをいじくり回すことを回避します。

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

クローズを効果的に処理する方法の詳細については、次のブログ投稿を参照してください:Java:ストリーム処理を混乱させない方法。より多くのサンプルコードとより深い深さがあり、キャッチブロックで閉じることの落とし穴をカバーしています。

于 2008-10-01T09:44:16.553 に答える
26

ストリームを閉じようとしたときに IOException をスローするか飲み込むかは、次のような方法で行う必要があります。

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}
于 2008-10-01T07:05:57.123 に答える
10

JDK7 で追加されたtry-with-resources機能を使用できます。この種のものに対処するために正確に作成されました

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

ドキュメントには次のように書かれています。

try-with-resources ステートメントは、各リソースがステートメントの最後で確実に閉じられるようにします。

于 2012-05-17T22:35:30.993 に答える
4

単純な静的ヘルパー メソッドを使用することもできます。

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

そして、finally ブロックからこれを使用します。

于 2008-10-01T07:12:03.550 に答える
3

非常にマイナーな文体の提案を除いて、追加することはあまりありません。 この場合、自己文書化コードの標準的な例が適用されIOExceptionますclose()

したがって、イカの答えは次のようになります。

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}
于 2008-10-01T08:12:45.637 に答える
2

ほとんどの場合、 IO 例外をキャッチせ、単純に try-finally を使用する方が良いことがわかりました。

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

を除いてFileNotFoundException、一般に を「回避」することはできませんIOException。残された唯一のことはエラーを報告することです。通常、それはコール スタックのさらに上で処理されるため、例外を伝播する方がよいと思います。

はチェック済み例外であるためIOException、このコード (およびそのすべてのクライアント) を宣言する必要がありますthrows IOException。それはうるさすぎるかもしれませんし、IO を使用する実装の詳細を明らかにしたくないかもしれません。その場合、IOExceptionaRuntimeExceptionまたは抽象例外タイプでラップする例外ハンドラーを使用して、ブロック全体をラップできます。

詳細:上記のコードは、ブロックtry内のclose操作で. これは大きな問題ではないと思います。一般に、ブロックからの例外は、ブロックが失敗する原因と同じです (つまり、IO が正常に動作し、閉じた時点で失敗することは非常にまれです)。これが懸念事項である場合は、クローズを「沈黙」させるのに苦労する価値があるかもしれません。finallyIOExceptiontryIOExceptionclose

于 2008-10-01T10:52:02.243 に答える
1

次の解決策は、クローズの前に可能な例外を非表示にすることなく、クローズが失敗した場合に正しく例外をスローします。

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

これは、close を 2 回呼び出しても効果がないため機能します。

これはguava Closeablesに依存していますが、squiddle で示されているように、必要に応じて独自の closeQuietly メソッドを作成できます( serg10参照)。

一般的なケースでは、クローズ エラーを報告することは重要です。なぜなら、クローズは、たとえばバッファリングのために、いくつかの最終バイトをストリームに書き込む可能性があるためです。したがって、ユーザーは失敗したかどうかを知りたいか、何らかの方法で行動したいと考えています。確かに、これは FileInputStream の特定のケースでは当てはまらないかもしれませんが、私にはわかりません (ただし、既に述べた理由から、とにかく発生した場合はクローズ エラーを報告する方がよいと思います)。

上記のコードは、try ブロックが埋め込まれているため、少しわかりにくいです。IOException をスローするメソッドと、IOException をキャッチするメソッドの 2 つのメソッドを使用すると、より明確になると考えられます。少なくともそれが私が選ぶものです。

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.htmlに基づく(McDowell が参照)。

于 2011-07-23T19:28:56.283 に答える
0

願わくば、いつか Java でクロージャを取得して、多くの冗長性を失うことになるでしょう。

代わりに、インポートできる javaIO のどこかにヘルパー メソッドがあり、おそらく "Closeable" インターフェイスとブロックを使用します。そのヘルパー メソッド内で、try {closable.close() } catch (IOException ex){ //blah} が一度だけ定義され、その後、次のように記述できるようになります。

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }
于 2008-10-01T07:18:51.070 に答える
-4

主に、FindBugs からクリーンなレポートを取得すること、または機能するコードを取得することに関心がありますか? これらは必ずしも同じものではありません。元のコードは問題ありません (そうでなければスローされif (fis != null)たので、冗長なチェックを取り除きます)。OutOfMemoryExceptionFileInputStream には、処理中に IOException を実際に受け取る可能性が低い場合に、ストリームを閉じるファイナライザー メソッドがあります。非常にありそうもないシナリオを回避するためにコードをより洗練されたものにするのは、単に価値がありません。

  1. IOException が発生し、
  2. これは非常に頻繁に発生するため、ファイナライザーのバックログの問題が発生し始めます。

編集:ファイナライザ キューで問題が発生するほど多くの IOExceptions を取得している場合は、はるかに大きな魚を揚げなければなりません! これは、視点の感覚を得ることです。

于 2008-10-01T08:37:48.117 に答える