さて、私は以下を行っています(変数名が変更されました):
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ライブラリはチェックされた例外を非常に多くスローします。
Java 7以上の場合 try-with-resources を使用する必要があります:
try (InputStream in = new FileInputStream(file)) {
// TODO: work
} catch (IOException e) {
// TODO: handle error
}
Java 6以下)で立ち往生している場合...
このパターンは、nullをいじるのを避けます。
try {
InputStream in = new FileInputStream(file);
try {
// TODO: work
} finally {
in.close();
}
} catch (IOException e) {
// TODO: error handling
}
closeを効果的に処理する方法の詳細については、次のブログ投稿を参照してください: Java:ストリーム処理を混乱させない方法 。より多くのサンプルコードとより多くの深さがあり、catchブロックでのcloseのラッピングの落とし穴をカバーしています。
ストリームを閉じようとするときに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)
{
}
}
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ステートメントは、ステートメントの終わりに各リソースが確実に閉じられるようにします。
単純な静的ヘルパーメソッドを使用することもできます。
public static void closeQuietly(InputStream s) {
if (null == s) {
return;
}
try {
s.close();
} catch (IOException ioe) {
//ignore exception
}
}
そしてあなたのfinallyブロックからこれを使用してください。
非常にマイナーなスタイルの提案を除いて、追加するものは何もありません。 自己文書化コードの標準的な例はこの場合に適用されます-close()
でキャッチする必要がある無視されたIOException
に説明的な変数名を付けます。
したがって、スクイドルの答えは次のようになります。
public static void closeQuietly(InputStream s) {
try {
s.close();
} catch (IOException ignored) {
}
}
ほとんどの場合、IO例外をキャッチし、単純にtry-finallyを使用するほうがnotのほうが良いと思います。
final InputStream is = ... // (assuming some construction that can't return null)
try {
// process is
...
} finally {
is.close();
}
FileNotFoundException
を除いて、通常、IOException
を「回避」することはできません。あとは、エラーを報告するだけです。通常は、コールスタックでさらに処理するので、例外を伝播するほうがよいと思います。
IOException
はチェック例外であるため、このコード(およびそのクライアント)はthrows IOException
であることを宣言する必要があります。それはうるさすぎるかもしれません、またはあなたはIOを使うことの実装詳細を明らかにしたくないかもしれません。その場合、IOException
をRuntimeException
または抽象的な例外タイプにラップする例外ハンドラーでブロック全体をラップできます。
詳細:上記のコードは、try
ブロックのclose
操作でfinally
が生成されるときに、IOException
ブロックからの例外を飲み込むことを認識しています。これは大きな問題だとは思いません。通常、try
ブロックからの例外は、IOException
が失敗する原因となるclose
と同じになります(つまり、IOが正常に機能することはまれですそして、クローズの時点で失敗します。これが問題である場合は、クローズを「沈黙」させることは、トラブルに値するかもしれません。
次の解決策は、クローズの前に起こり得る例外を隠さずにクローズが失敗した場合に、例外を正しくスローします。
try {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
} catch(IOException exc) {
// kernel panic
}
これは、もう一度closeを呼び出す 効果がない であるため機能します。
これはguava Closeables に依存しますが、 squiddle で示されるように、必要に応じて独自のcloseQuietlyメソッドを記述できます( serg1 も参照)。
Closeはストリームに最終バイトを書き込む可能性があるため、一般的なケースでは、closeエラーを報告することが重要です。バッファリングのため。そのため、ユーザーは失敗したかどうかを知りたいか、おそらく何らかの方法で行動したいと考えています。確かに、これはFileInputStreamの特定のケースでは当てはまらないかもしれませんが、わかりません(ただし、すでに述べた理由から、とにかく発生した場合は、閉じるエラーを報告する方がよいと思います)。
上記のコードは、埋め込まれたtryブロックの構造のため、理解するのが少し難しいです。 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によって参照)に基づいています。
うまくいけば、私たちはJavaでいつかクロージャを取得し、それから多くの冗長性を失うでしょう。
そのため、代わりにjavaIOのどこかにインポートできるヘルパーメソッドがあり、おそらく「Closable」インターフェースとブロックが必要になります。そのヘルパーメソッド内では、try {closable.close()} catch(IOException ex){// blah}が一度だけ定義され、その後、次のように記述できます。
Inputstream s = ....;
withClosable(s) {
//your code here
}