私たちは彼とそれについていくらか詳細に話し合いました、そして彼は私が何が起こるかを正確に知っているなら私はフォールバックを試みる/キャッチすることに頼らずにそれを処理しようとするべきであるという線に沿って何かを言っていました。
インストラクターがIO例外を回避するためにテストする必要があると言っている場合は、彼が単に間違っているのではないかと心配しています。
ほとんどのI/O操作IOException
は、チェックされた例外であるスローとして宣言されます。これらのメソッドを呼び出すとき、コードは例外を処理または伝播する必要があります。あなたは選択肢がありません。Java言語では、チェックされたすべての例外に対してこれが義務付けられています。
考えられるすべてのIOExceptionをテストすることは実用的ではありません。たとえば、このコードは失敗する可能性があります。
if (f.exists() && f.canRead()) {
os = new FileInputStream(f);
}
なんで?ハードディスクエラー、ネットワークエラー(ファイルがリモートマウントされたファイルシステム上にある場合)、強制アクセス制御の失敗など、コンストラクターがIOExceptionをスローする理由は他にもあるためです。多くの場合、根本的な状態は、ファイルを開こうとする以外の方法では検出できません。
次に、競合状態の問題があります。上記の例では、ファイルが読み取り可能であることをテストしてから開こうとするまでに、わずかな時間枠があります。その時間枠内で、他のスレッドまたは外部プロセスがファイルを削除するか、そのアクセスを変更して、開くことが失敗する可能性があります。その時間枠を閉じる方法はありません。
次に、なぜ例外を避けたいのかという問題があります。あなたの先生は「例外デニール」だと思います。つまり、「例外は例外的なものにのみ使用されるべきである」というアドバイスを非論理的な極端に受け止めている人々の1人です。
「例外は例外的なものにのみ使用する必要があります」というアドバイスは、基本的に、例外は高価であるため、使いすぎてはいけないと言っています。しかし、高価なのは相対的です。
この例では、toFile.exists()
とtoの呼び出しFile.canRead()
も、それぞれがシステムコールを伴うため、コストがかかります。これには、数千クロックサイクルかかります。さらに悪いことに、アプリケーションに異常がない限り、これら2つのテストは成功します...したがって、とにかくスローされない例外を回避するために、2つの不要なシステムコールを実行しました。これらのテストが失敗する可能性が高い(つまり> 50%)場合を除いて、テストをスキップし、オープンを試行して、例外が発生した場合はそれを処理する方が効率的です。
私は自分の教授にそのようなラベルを付けません。I / Oの複雑さについては特に話しませんでした。それは、私がそれを避けることができれば、それを避けるべきであるという、より一般的な用語でした。非常に避けられない例外があることを私は知りませんでした(そして彼はその詳細に立ち入りませんでした)。
わかった。だからあなたの教授はそれを言わなかった。彼にとって良かった。
そして、はい、それらは複数の意味で避けられません。
.exists()チェックの使用を拒否することに関して、パフォーマンスへの影響はそれほど重要ですか?
はい。これを参照してください-Syscallオーバーヘッド
または、それが信じられない場合は、マイクロベンチマークを作成して測定してください。そして、それを例外をスローしてキャッチするオーバーヘッドと比較してください。
たとえば、デスクトップとモバイルなどの問題でしょうか。
いいえ。または、オペレーティングシステムが仮想メモリを使用して1つの「アプリ」が別の「アプリ」に干渉するのを防ぐモバイルの場合は確かにそうではありません。
トラブルシューティング/デバッグ(プログラムのクラッシュを回避しながら問題をより正確に特定できる場合)の明確さに対するトレードオフは、それだけの価値がありますか?
まあ、私はこのコードを主張します:
try (InputStream is = new FileInputStream(f)) {
// use file
} catch (IOException ex) {
System.err.println("IO error: ": ex.getMessage());
}
...これよりもシンプルで保守とデバッグが簡単です。
if (!f.exists()) {
System.err.println("File " + f + " does not exist");
} else if (!f.isDirectory()) {
System.err.println("File " + f + " is a directory");
} else if (!f.canRead()) {
System.err.println("File " + f + " is not readable");
} ...
} else {
try (InputStream is = new FileInputStream(f)) {
// read
} catch (IOException ex) {
System.err.println("IO error: "+ ex.getMessage());
}
}
同意しませんか?