Javaのファイナライズに関していくつか質問があります。たとえば、FileHelperクラスが1つあり、このクラスはファイルの読み取り、ファイルの書き込みなどに関連付けられています。今私の質問は、FileHelperクラスに1つのメソッドwriteFile()があります。そのファイルを閉じたい場合は、finalize()メソッドをオーバーライドしてファイルを閉じる必要がありますか、それともwriteFile()メソッド自体の中でファイルを閉じることができますか?どちらが正しい方法ですか?File変数をメンバー変数として宣言しました。オーバーライドが悪い考えである場合、なぜfinalize()メソッドをオーバーライドしたいのですか?どのシナリオ?私は多くの記事を読みましたが、ファイルやフォントなどのシステムリソースを閉じるように言われています。
4 に答える
ベスト プラクティスは、できるだけ早くファイルを閉じることです。FileHelper に静的メソッドがある場合 (ヘルパーが静的な「ヘルパー」メソッドの束であると仮定して)、内部のファイルを閉じます。
static void writeFile(String fileName, String text) { // Exception
// Open file here
// write text
// close it
}
finalize をオーバーライドする目的は、管理されていないリソース (ファイルなど) を誰かが忘れた場合に解放することです。誰かがあなたのヘルパーをこのように使用した場合
FileHelper fileHelper = new FileHelper(file);
fileHelper.writeFile(text);
// forgot to fileHelper.close();
ファイナライズをオーバーライドし、GC の実行時に内部で close() を呼び出すと、ファイルが閉じられます。問題点:
- 先に述べたように、ファイルはできるだけ早く閉じる必要があります(ただし、すぐにではありません;))
- 不確定です(GCがいつ開始されるかは誰にもわかりません)
- これは、呼び出し元がファイルを閉じるのを忘れた場合にのみ使用する必要があります。
ほぼすべての状況で、ファイナライザーを使用することはお勧めできません。Java 仕様では、ファイナライザーが実行されるという保証はないと述べています。仮にそうなったとしても、それがいつ起こるかを制御することはできません。
ファイルを閉じるための主要なメカニズムとしてファイナライザーを使用することは、常に悪い考えです。なんで?GC が長時間実行されないと、アプリケーションでファイル記述子が不足する可能性があり、ファイルを開く試みが失敗し始めるためです。
開いたストリームを処理する最善の方法は、それらをローカル変数とパラメーターに保持し、それらを使いtry { ...} finally
終わったときに常に閉じていることを確認するために使用することです。または、Java 7 では、新しい「try with resource」構文を使用します。
ストリームをメンバー変数に入れる必要がある場合は、ストリームclose()
を閉じるメソッドを親クラスに実装し、親クラスtry { ...} finally
のインスタンスが確実に閉じられるようにする必要があります。
また、「失われた」ストリームを閉じるためにファイナライザを使用する意味はほとんどないことに注意してください。クローズする必要がある外部リソースを使用するストリーム クラスには、これを行うためのファイナライザーが既にあります。
finalize() メソッドは、Java ガベージ コレクタがオブジェクトを回収しようとしているときにのみ呼び出されます。finalize メソッドでファイル ハンドルを解放するのは悪い習慣です。
java.io.IOException: Too many open files が発生する可能性があります。これは、ガベージ コレクターがいつ実行されるかを保証できないためです。
より良いオプションは、finally ブロックでファイル リーダー/ライター オブジェクトを閉じることです。実行が保証されているためです。
finally {
// Always close input and output streams. Doing this closes
// the channels associated with them as well.
try {
if (fin != null)
fin.close();
if (fout != null)
fout.close();
} catch (IOException e) {
}}
fin と fout は FileInputStream と FileOutputStream オブジェクトです。
finalize()をオーバーライドすることは良い習慣ではありません。私はコードでそれをしたでしょう。