_public Path createPath(String name){
return Files.createFile( Paths.get( name ) );
}
_
createPath(String name)
では、Java.nio.file.FilesがJava.io.IOExceptionをスローします。ただし、これはより大きなライブラリで使用されます。そして、私は巨大です。メソッドシグネチャに例外を追加するだけの場合、それは、より大きなライブラリがそれを使用するすべてのメソッドにも例外を追加する必要があることを意味します。トライキャッチでラップすると、おそらく1日を節約できますが、コードが見苦しくなります。 (私の目で):
_public Path createPath(String name){
Path file = null;
try {
file = Files.createFile( Paths.get( name ) );
} catch ( IOException e ) {
e.printStackTrace();
}
return file;
}
_
これのための最良のアプローチは何でしょうか?
次の2つのオプションが考えられます。
createPath
は例外を飲み込み、アプリケーションはNullPointerException
。のどこかでクラッシュします。RuntimeException
またはError
またはそれらのいずれかのサブクラスをスローすることです。main
までのコールチェーン全体にthrows IOException
を追加し、IOException
でアプリケーションをクラッシュさせます。ただし、チェック済み例外(または一般的な例外)の背後にある実際の意図は異なります。
throws IOException
を、ファイルを作成できない場合の対処方法を知っている呼び出し元までのコールチェーンに追加します。呼び出し元はIOException
をキャッチして処理します。次の例を検討してください。
import Java.io.IOException;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.Paths;
import Java.util.Scanner;
public class App {
private Scanner reader;
public App() {
reader = new Scanner(System.in);
}
public String getPathFromUser() {
System.err.print("Enter a path: ");
return reader.nextLine();
}
public Path createPath(String name) throws IOException {
return Files.createFile(Paths.get(name));
}
public Path promptForPath() {
while (true) {
String path = getPathFromUser();
try {
return createPath(path);
} catch (IOException e) {
System.err.printf("Unable to create %s (%s)\n", path, e);
continue;
}
}
}
public static void main(String[] args) {
App app = new App();
Path path = app.promptForPath();
// do stuff with path
}
}
ここでmain
はpromptForPath
を呼び出し、次にcreatePath
を呼び出します。
promptForPath
はそのIOException
を処理する方法を知っているため(ユーザーに別のパスを要求します)、throw IOException
でマークする必要はありません。createPath
はその処理方法を認識していないため、throw IOException
である必要があります。main
もそれを処理する方法を知りません-しかし、promptForPath
がすでにそれを処理したので、それをする必要はありません。throws
句を使用してコールスタック内のメソッドを汚染するか、createPath
...try
を使用してcatch
を醜くする方が良いですか?
これらのものは、間違った場所に置かれたときにのみ醜くて扱いにくいです。適切な場所に配置すると、醜い汚染ではなく、ロジックの一部として実際に適合できます。
質問のtry
のcatch
...createPath
は、醜いコード臭です-それが存在することは明らかですhide a問題。一方、try
のcatch
...promptForPath
は、問題を処理しているため、見苦しくありません。
同様に、トップレベルのメソッドのthrows IOException
は醜いです-なぜあなたのmain
がIOException
をスローするのでしょうか?しかし、パスを取得する下位のメソッドでは意味があります( "このメソッドはパスを処理し、存在しないパスに遭遇する可能性があります")ので、醜くない-それらは署名の役に立つ部分です。
考慮すべきもう1つのこと:例外を完全にバブリングする場合は、1つの例外を別の例外に置き換えるだけです。それが仕事の価値があるかどうかわからない。しかし、それを処理できるポイントまでバブルしている場合は、アプリケーションの品質が向上します。たとえば、クラッシュする代わりに、入力したパスが無効であることをユーザーに通知し、入力を促す新しいもの。これはユーザー側からの望ましい動作であり、リファクタリングを価値のあるものにします。
何よりもまず、正しい答えはこの1つの簡単な質問に対処する必要があります。
この方法ではどのような保証が必要ですか?
要するに、要件は何ですか?ファイルを作成するメソッドをリクエストしていて、そのファイルを作成しない場合は、その目的を満たしていません。そのファイルを作成できない理由には、アクセス許可から、ファイルを作成することになっているパスが存在しない、または存在できないなど、さまざまな理由が考えられます。
この時点で、3つのオプションがあります。
この場合、ファイルを作成できない場合、所有しているライブラリがその状態から回復し、別のファイルを作成できる可能性があります。または、回復できない可能性があり、その大きなライブラリを使用しているエンドコードに何かが本当に間違っていることを通知する前に、いくつかのクリーンアップを行う必要があります。
問題を黙って無視することで、ライブラリを作成していますassume操作が正常に完了しなかったときに正常に完了しました。無効な仮定は、微妙なエラーではなく、微妙なエラーの原因となります。操作の成功または失敗を明確に伝えて、その関数を使用するコードが既知の状態で操作できるようにする必要があります。
例外がチェックされるかどうかの問題は、どのような苦痛を我慢したいのかの1つです。
例外がスローされると思われる可能性と、例外が直接処理されない場合のシステムへの影響の大きさに基づいて、決定を行う必要があります。