web-dev-qa-db-ja.com

Javaのメソッドごとに大きなtry-catchを使用することは既知の良い習慣ですか?

最近インタビューを受けたので、インタビュアーは私の知識を見るために技術的なテストをしてほしいと言っていました。私がそれを終えた後、彼は私がそれをどうやってやったかについてのフィードバックをくれました。

彼が私のコードについて悪いと思ったと言ったことの一つは、私が書いた各メソッド内で複数のtry-catchブロックを使用したことです。面白いと思うので、これは私の注意を呼びます。

現時点では、キャッチする必要のある例外をスローできる1つ以上のメソッドを持つ、意味的に区別可能なコードブロックがあるtry-catchブロックを作成する必要があると考えています。私が従った唯一の例外は、2つのメソッドが同じ例外タイプをスローする場合、例外をスローする場所と理由をデバッグするときに明確に区別するために、それらを異なるtry-catchブロックに配置することです。

これは、インタビュアーが私に望んでいたこととは大きく異なります。メソッドごとに1つのtry-catchブロックを使用することは、既知の優れたプラクティスですか?それが既知の優れた実践である場合、それを行うことの利点は何ですか?

編集:これについてのあなたの考えを大いに感謝します、これは非常に良いです。それが既知の良い慣行であるかどうか尋ねていることに注意してください。これは、ほとんどのプログラマがこれに同意するかいくつかの本で良い習慣として書かれています

56
Adrián Pérez

私にとっては、2つのtry-catchブロックでほとんどのメソッドが長すぎます。メソッドが多くのことをしている場合、意図をわかりにくくします。

2つのtry-catchブロックを使用すると、正確には少なくとも4つのことを実行します

  • メインフローの2つのケース(2つのtryブロック)
  • エラー処理の2つのケース(キャッチブロック)

私はそれぞれのtry-catchブロックから短くて明確なメソッドを作りたいです

private getHostNameFromConfigFile(String configFile, String defaultHostName) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(configFile));
        return reader.readLine();
    } catch (IOException e) {
        return defaultHostName;
    }
}
public Collection<String> readServerHostnames(File mainServerConfigFile, File  backupServerConfigFile) {
    String mainServerHostname=getHostNameFromConfigFile(mainServerConfigFile,"default- server.example.org");
    String backupServerHostName=getHostNameFromConfigFile(backupServerConfigFile,"default- server.example.ru")
    return Arrays.asList(mainServerHostname,backupServerHostName );
}

「クリーンコード」のロバートC.マーティンは、次のレベルを提案します。

キーワード 'try'が関数に存在する場合、それは関数の最初のWordであり、catch/finallyブロックの後には何もないはずです。

2つの独立したtry/catchブロックを使用してメソッドを小さなメソッドにリファクタリングすることは間違いありません。

36
Bartosz Bilicki

try/catchを使用して2つの別個のコードブロックをラップしている場合は、それらのブロックを個別のメソッドにリファクタリングすることを検討する必要があります。これがインタビューで使用したパターンである場合は、おそらくインタビュアーを誤解している可能性があります。

アルゴリズムで必要な場合、2つのtry/catchブロックを使用しても問題ありません。安全なクリーンアップを確実にするためにcatchブロックで新しいtry/catchを頻繁に使用して、ブランケットステートメントを使用できないようにしました。

30
OldCurmudgeon

あなたの質問に答えるために、実際にコードで多くの最適化を適用している現代のJVMについて話すとき、非効率的なコードを書くと、JVMは自動的に最適化を導入します。

Java: "try-catch"ブロックの入力/使用のオーバーヘッド? )の回答を参照してください。

したがって、優れた実践はそれほど重要ではありません。

個人的には、try-catchstaticsynchronizedなどのブロックに不必要にカプセル化しないでください。

これに取り組んでいる人にとってコードをより読みやすくしましょう。例外がキャッチされた場合、どのコードが例外をスローしているのかを明確に目立たせることをお勧めします。

読者には推測がつかないので、JVMが賢く、好きなように書いて、人間にとってより良いものにし、JVMが最適化の部分を処理します。

EDIT:私はたくさんの本を読んだことがありますが、1つの大きなtry catchが複数の小さなtry catchよりも優れていると言う場所は見つかりませんでした。

さらに、開発者コミュニティの多くは反対を信じています。

13
dharam

Catchブロックでの重複を避けるようにします。メソッド内のすべての例外がcatchブロックで同じ処理を受け取る場合は、先に進み、それらをすべてまとめてキャッチします。それらで別のことをする必要がある場合は、それらを別々にキャッチします。

たとえば、ここですべての例外を一緒にキャッチできます。これは、あらゆる種類の例外がメソッド全体の失敗を意味するためです。

public PasswordAuthentication readAuthenticationDetails(File authenticationFile) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(authenticationFile));
        String username = reader.readLine();
        String password = reader.readLine();
        return new PasswordAuthentication(username, password.toCharArray());
    } catch (IOException e) {
        return null;
    }
}

これに対して、コールのグループごとに異なるフォールバック動作があるため、個別にキャッチします。

public Collection<String> readServerHostnames(File mainServerConfigFile, File backupServerConfigFile) {
    String mainServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(mainServerConfigFile));
        mainServerHostname = reader.readLine();
    } catch (IOException e) {
        mainServerHostname = "default-server.example.org";
    }

    String backupServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(backupServerConfigFile));
        backupServerHostname = reader.readLine();
    } catch (IOException e) {
        backupServerHostname = "default-server.example.ru";
    }

    return Arrays.asList(mainServerHostname, backupServerHostname);
}

(このコードは、例外をキャッチすることに関するこの点を説明するために純粋に存在します;他の方法では全く恐ろしいという事実を無視してください)

9
Tom Anderson

私に関しては、try-catchメソッド内のすべての「危険な」コードをラップするブロック。 2行で同じ例外がスローされた場合の責任者については、常にスタックトレースがあります。

さらに、複数のtry-catchは通常、複数のreturn行を持つことを意味します(一目でコードの実行を追跡するのが難しくなる可能性もあります)。最初のtry-catch、残りのコードを実行し続けることは意味がありません。

ここでは、役に立つと思われる場合に備えて、いくつかの「標準的な」ベストプラクティスを見つけることができます。

http://howtodoinjava.com/2013/04/04/Java-exception-handling-best-practices/

6
ssantos

これは、Java-flamewarを頻繁に開始する別のことです... ;-)

基本的に、パフォーマンスの問題は例外のスローのみです。したがって、_try-catchブロックは、パフォーマンスにまったく影響しません。そのようにコードを書くとコードが難読化され、「クリーンなコード」さえ思い出せないという意見もあれば、実際に例外をスローできる行にのみtryを使用した方が良いと考える意見もあります。

決定するのはチーム次第です。

5
Eel Lee

コードのコンテキストを考慮することも重要です。重いIOでコードを書いている場合は、コードのどの部分が失敗しているかを知る必要があるかもしれません。問題から回復する機会を与えてください。

したがって、1つのファイルからの読み取りでIO例外が発生した場合は、読み取りを再試行することをお勧めします。書き込みと同じです。しかし、1つの大きなtry ... catch再試行します。

5
Chris