学校のプロジェクトに取り組んでいる間に、次のコードを書きました。
_FileOutputStream fos;
ObjectOutputStream oos;
try {
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(shapes);
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) oos.close();
if (fos != null) fos.close();
}
_
問題は、Netbeansがresource.close()
行がIOException
をスローすることを通知しているため、キャッチまたは宣言する必要があることです。また、oos
とfos
がまだ初期化されていない可能性があることにも不満を感じています(nullチェックにもかかわらず)。
IOException
をそこで停止することが全体のポイントであると考えると、これは少し奇妙に思えます。
私のひざの修正はこれを行うことです:
_} finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
} catch (IOException ex) { }
}
_
しかし、これは私を悩ませ、汚く感じます。
私はusing
ブロックを単に利用するC#のバックグラウンドから来ているので、これを処理するための「正しい」方法が何であるかはわかりません。
isこの問題を処理する正しい方法は何ですか?
ソースですべての例外をキャッチして報告しようとしている場合、より良い解決策は次のとおりです。
_ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(shapes);
oos.flush();
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException ex) {
// ignore ... any significant errors should already have been
// reported via an IOException from the final flush.
}
}
}
_
ノート:
close
およびflush
をラップされたストリームに伝播します。したがって、最も外側を閉じるかフラッシュするだけです。ラッパー。IOException
の(実際の)ハンドラーが書き込みエラーを確認できるようにすることです。1。「IOExceptionsを無視してnullの可能性があるストリームを閉じる」必要がある場合は、次のようなヘルパーメソッドを自分で作成できます。
_public void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ex) {
// ignore
}
}
}
_
次に、前のfinallyブロックを次のように置き換えることができます。
_} finally {
closeQuietly(oos);
}
_
(別の答えは、Apache CommonsライブラリでcloseQuietly
メソッドが既に利用可能であることを指摘しています... 10行のメソッドのプロジェクトに依存関係を追加することを気にしない場合。[〜# 〜] update [〜#〜]:これらのメソッドはAPIバージョン2.6で廃止されることに注意してください。)
ただし、IO例外reallyが無関係であるストリームでのみcloseQuietly
を使用することに注意してください。
1-try-with-resourcesを使用する場合、これは必要ありません。
人々が尋ねているflush()
対close()
の問題について:
close()
によりすべてのバッファー付き出力がフラッシュされることを示すAPIコントラクトがあります。 shouldは、出力バッファリングを行う他のすべての(標準)出力クラスが同じように動作することを発見します。したがって、標準クラスでは、flush()
の直前にclose()
を呼び出すことは冗長です。close()
メソッドは間違いなく壊れた。最後に、flush()
が実際に行うことの問題があります。 javadocが言うことはこれです(OutputStream
の場合...)
このストリームの目的の宛先が、基礎となるオペレーティングシステム(ファイルなど)によって提供される抽象化である場合、ストリームをフラッシュすると、以前にストリームに書き込まれたバイトのみが書き込みのためにオペレーティングシステムに渡されます。ディスクドライブなどの物理デバイスに実際に書き込まれることを保証するものではありません。
だから... flush()
を呼び出すことでデータが持続することを保証することを期待/想像するなら、あなたは間違っています!(そのようなことをする必要があるなら、 _FileChannel.force
_メソッド...)
一方、Java 7以降を使用できる場合は、@ Mike Clarkの答えで説明されている「新しい」try-with-resourcesが最適なソリューションです。
新しいコードにJava 7以降を使用していない場合は、おそらく深い穴にあり、より深く掘っています。
クローズ可能なオブジェクト(ファイルなど)を含むtry/catch/finallyの現在のベストプラクティスは、Java 7のtry-with-resourceステートメント、たとえば:
try (FileReader reader = new FileReader("ex.txt")) {
System.out.println((char)reader.read());
} catch (IOException ioe) {
ioe.printStackTrace();
}
この場合、FileReaderはtryステートメントの終わりで自動的に閉じられ、明示的なfinallyブロックで閉じる必要はありません。ここにいくつかの例があります:
http://ppkwok.blogspot.com/2012/11/Java-cafe-2-try-with-resources.html
公式Javaの説明は次のとおりです。
http://docs.Oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
Java 7は 自動リソース管理 ブロックを追加します。これらはC#のusing
に非常に似ています。
Josh Blochが 技術提案 を書いたので、読むことを強くお勧めします。これは、今後のJava 7言語機能に足を踏み入れるためだけでなく、仕様がそのような構成の必要性を動機付けるためであり、そうすることで、正しいコードを書く方法を示しますARMがない場合でも。
ARM形式に変換されたAskerのコードの例を次に示します。
try (FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos))
{
oos.writeObject(shapes);
}
catch (FileNotFoundException ex)
{
// handle the file not being found
}
catch (IOException ex)
{
// handle some I/O problem
}
私は通常、次のようなメソッドを持つ小さなクラスのIOUtilを持っています。
public static void close(Closeable c) {
if (c != null) {
try {
c.close();
}
catch (IOException e) {
// ignore or log
}
}
}
この男はどうですか? nullチェックなし、驚きなし。すべてが終了時にクリーンアップされます。
try {
final FileOutputStream fos = new FileOutputStream(file);
try {
final ObjectOutputStream oos = new ObjectOutputStream(fos);
try {
oos.writeObject(shapes);
oos.flush();
}
catch(IOException ioe) {
// notify user of important exception
}
finally {
oos.close();
}
}
finally {
fos.close();
}
}
catch (FileNotFoundException ex) {
// complain to user
}
catch (IOException ex) {
// notify user
}
残念ながら、言語レベルのサポートはありません。しかし、これを簡単にする多くのライブラリがあります。 commons-ioライブラリを確認してください。または、最新のgoogle-guava @ http://guava-libraries.googlecode.com/svn/trunk/javadoc/index.html
あなたはそれを正しくやっています。それは私もがらくたを悩ます。これらのストリームを明示的にnullに初期化する必要があります-これは一般的な規則です。できることは、クラブに参加してusing
が欲しいだけです。
あなたのポイントへの直接的な答えではありませんが、finally
とcatch
は両方ともtry
に関連付けられているので、人々は彼らが一緒にいると思います。 try
ブロックの最適な設計は、catch
またはfinally
のいずれかを持ち、両方は持たないことです。
この場合、コメントは何かが間違っていることを示唆しています。ファイルIOを扱うメソッドで、ユーザーに何か不満を言うのはなぜですか。ユーザーが見えない場所でサーバーを深く実行している可能性があります。
したがって、上記のコードには、問題が発生したときに正常に失敗するようにfinally
が必要です。ただし、エラーをインテリジェントに処理する能力が不足しているため、catch
はコールチェーンの上位に属します。