16

try/catchブロック内に配置するコードの量に関する「ベスト プラクティス」はありますか?

以下に3つの異なるシナリオを投稿しました。

catchブロックに動作を含めず、finally ブロックも含めませんでした。これは、視聴者の読みやすさを向上させるためでした。それぞれが異なることをすると仮定catchします。finallyそして、がストリームを閉じると仮定します。将来の読者のために読みやすい例を作成しようとしています。

  1. コントロール、いいえtry/catch
  2. try/catch必要な場所ごとに 1 のコード。
  3. try/catchコード ブロック全体を 1 つだけ囲むコード。

一般的にベスト プラクティスとして受け入れられているものとその理由は何ですか?


シナリオ 1

try/catch制御のためだけに、なしでコード化します。

    BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
    bufferedReader.close();

シナリオ 2

try/catch必要な個々の場所ごとにブロックを使用してコードを作成します。

    BufferedReader bufferedReader = null;
    try {
        bufferedReader = new BufferedReader(new FileReader("somepath"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    String line;
    try {
        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            this.doSomething(object);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        bufferedReader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

シナリオ 3

try/catchコードのブロック全体を 1 で囲んだコード。

    try {
        BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            this.doSomething(object);
        }
        bufferedReader.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
4

10 に答える 10

14

次の基準に基づいて、try/catch のスコープを設定する必要があります。

  • 例外がどこから来たかに基づいて、異なることをする必要がありますか?
  • どの例外がスローされたかに基づいて、さまざまなことを行う必要がありますか?
  • 特定の例外がスローされたときに、どのコードをスキップする必要がありますか (別名「無効」)?

これらの質問に答えると、try/catch ブロックの適切なスコープを決定できます。

于 2013-10-24T15:15:28.810 に答える
7

私はできるだけtry-catchに入れませんでした。

これにより、コードの断片を別々のメソッドに簡単に移動できます。これは、優れたコーディング プラクティスです (単一責任の原則に従います。Robert C. Martin 著の「Clean Code: A Handbook of Agile Software Craftsmanship」という本を参照してください)。

もう 1 つの利点は、どのコードが実際に例外をスローできるかをすばやく特定できることです。

ただし、シナリオ 2 は少し極端に思えます。方法がかなり小さいため、シナリオ 3 が最適な選択のようです。

ただし、finally ブロックに「close」ステートメントを含める必要があります。

于 2013-10-24T15:16:43.190 に答える
2

これは意見の問題です。私はこれらのパターンのそれぞれをたくさん見てきました。

パターン 1 は、メソッドが例外をスローし、呼び出し元チェーンで何かを処理できる場合にのみ有効です。それはしばしば望ましいことです。ただし、close呼び出しは にないため、呼び出さfinally blockれない可能性があります。少なくとも、try-finallyブロックを使用してください。

パターン 2 は良くありません。最初の try-catch ブロックが例外を処理すると、残りのメソッドは役に立たなくなるからです。

パターン 3 は問題ありませんが、スタック トレースを出力すると、操作が失敗したという事実が隠されるため、あまり良くありません。操作が行われていないのに行われたと思われる場合、呼び出し元は何をしますか。また、closes が発生しなかった可能性があり、プログラムの失敗につながる可能性があります。

疑似コードでは、パターン 3 のこのバリアントの方が優れています。

Declare Streams, connections, etc.
try
    Initialize streams, connections, etc,
    Do work.
catch (optional)
    Catch and handle exceptions.
    Do not simply log and ignore.
finally
    Close connections and streams in reverse order.
    Remember, closing these objects can throw,
        so catch exceptions the close operation throws.
End.

Java 7 を使用している場合は、try-with-resources を使用します。

try (BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"))) {
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
}

呼び出しIOException元にバブルアップします。

于 2013-10-24T15:28:13.630 に答える
1

私はException無条件に返される結果の型であると考えています。したがって、try-catch セクションで作業するときは、質問に答えようとしています。

  1. ここで予期しない結果を処理する必要がありますか、それともより高いレベルで伝播する必要がありますか?
  2. どの予期しない結果を処理する必要がありますか?
  3. それらをどのように処理しますか?

In 95% of the cases I don't go further than the first point, so I just propagate the errors.

For file processing I use try-with-resources an re-throw the IOException with throw new RuntimeException(e).

于 2013-10-24T15:27:49.210 に答える
1

3 番目のシナリオを使用する必要があります。

bufferedReader が例外にヒットした場合、2 番目のシナリオでの作成時にそれを実行しようとするreadLine()と、別の例外にヒットします。同じ問題に対して複数の例外を発生させても意味がありません。

また、finally ブロックで bufferedReader を閉じる必要があります。

BufferedReader bufferedReader;
try {
    bufferedReader = new BufferedReader(new FileReader("somepath"));
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (bufferedReader != null)
        bufferedReader.close(); 
}
于 2013-10-24T15:17:59.750 に答える
0

スタック トレースを出力して続行するだけなので、try/catch を 1 つずつ使用する例は意味がありません。失敗することは既にわかっています。全体を試してキャッチするか、スロー SomeException をメソッド シグネチャに追加して、呼び出し元のメソッドに問題の原因を判断させることもできます。

また、try/catch 内で絞り込みすぎても心配しないでください。そのコードはいつでも別のメソッドに抽出できます。読みやすさは、プログラミングの最も重要な側面の 1 つです。

于 2013-10-24T15:15:00.357 に答える
0

3 番目のオプションは確かに最適です。try/catch ブロックが扱いにくくなることは望ましくありませんが、この例では十分に短いため、2 番目のオプションで行ったように分割する必要はありません。

于 2013-10-24T15:16:28.560 に答える
0

メソッドに入れるコードの量も似ていると思います。1 画面しかかからない try/catch/finally を書いてみてください。メソッド本体全体を try{} ブロックにラップすることは問題ではないと言いたいのですが、コードが長くなりすぎる場合は、このコードをいくつかのメソッドに分割する必要があります。

于 2013-10-24T15:13:55.187 に答える
0

シナリオ 2 ではありません。FileReader または BufferedReader コンストラクターがスローした場合、bufferedReader は null になりますが、次の try/catch は引き続き実行されます。したがって、bufferedReader.readLine で (キャッチされない) 例外、つまり NullPointerException が発生します。シナリオ 1 と 3 の間では、発信者がキャッチする必要がないため、一般的には 3 つ以上のシナリオを好みます。ところで、FileNotFoundException を明示的にキャッチする必要はありません。なぜなら、それは IOException から継承されているため、catch ブロックは両方をキャッチするからです。

于 2013-10-24T15:18:09.430 に答える