5

Java で例外をスローすることについて質問があります。これは、私の側からの一種の誤解であるように思われます。これについては、自分で明確にしたいと思います。

例外コードを処理する2つの基本的な方法は次のとおりです。

1.) 「throw new ...」を使用して try ブロックで例外をスローし、catch ブロックですぐにキャッチする - いわゆる try-throw-catch メカニズム。

2.) 「throw new ...」を使用してメソッドで例外をスローし、メソッドのヘッダーで、このメソッドが「throws ...」を使用して例外をスローする可能性があることを宣言する - いわゆるパスザバック。

最近、「例外をスローして同じメソッドでキャッチしても意味がない」という記事を読んで、私の理解が間違っているのか、これを書いた人に何かあったのかと思いました。他に念頭に置いてください。例外を処理する最初の方法はまさにこれ (try-throw-catch メカニズム) ではありませんか? つまり、例外をスローし、同じメソッドでキャッチします。あるメソッドで例外をスローし、別のメソッドで例外をキャッチする方が良い方法であると読みましたが、これは 1 つの (おそらくより良い) 方法です。他の方法も合法で正しいですね。

これについてコメントをいただけますか?どうもありがとうございました。

4

11 に答える 11

21

メソッドが独自に例外を解決できない場合、そのメソッドから例外をスローする必要があります。

たとえば、 FileInputStream 自体はファイルが見つからない場合を処理できないため、 aFileNotFoundExceptionがスローされます。エンドユーザー アプリケーションが問題を処理できるように、その例外をスローする必要があります。new FileInputStream(new File(filename))

メソッド内で例外を処理できる場合があります。たとえば、 をスローするドキュメント モデル メソッドBadLocationExceptionは、十分にインテリジェントなメソッド内で処理できます。問題に応じて、例外を処理するか再ス​​ローすることができます。

(とにかく、try-catch ブロック内から例外をスローして、catch ブロックを実行できるようにすることは、本当に悪いロジック フローを表していると私は主張します)

于 2009-02-09T14:58:28.543 に答える
6

最初のケースを誤解していると思います。通常、例外をスローする可能性のあるメソッドを呼び出すときに、try-catch-block を追加します。ローカルでスローされた例外をキャッチすることは、実際にはあまり意味がありません。特に、例外を使用してループを終了するべきではありません。これは、標準的なアプローチに比べて非常に遅いためです。

于 2009-02-09T14:55:27.877 に答える
4

例外を処理する最初の方法はまさにこれを行いませんか (try-throw-catch メカニズム)。つまり、例外をスローし、同じメソッドでキャッチします。

それは「例外を処理する方法」ではありません - それはまったくナンセンスです。例外の全体的なポイントは、コール スタックの別のメソッドがそれを処理できるようにすることです。同じメソッド内で条件を処理する場合、例外を使用しても意味がありません。それが if() の目的です! それによってメソッドの制御フローが複雑になりすぎる場合は、おそらくロジックの一部を別のメソッドにリファクタリングする必要があります。その後、残りのメソッド本体がキャッチする例外をスローするようにすることが理にかなっている場合があります。

そうは言っても、同じメソッドで例外をスローしてキャッチすることが理にかなっている特別なケースを想像できます。例外をスローする可能性があり、それを処理するための catch ブロックを持つメソッドを既に呼び出している場合場合によっては、例外をスローして、既存の catch ブロックが同じ方法で処理できる同様の問題を示すことが理にかなっている場合があります。

于 2009-02-09T15:11:54.733 に答える
2

最初の方法では、次のような意味ですか。

try {
  ok = doSomething();
  if (!ok) {
   throw new Exception("Error");
  }
 ok = doSomethingElse();
}catch (Exception e) {
}

これにより、残りの部分を実行せずに try-catch ブロックを終了できます。これは、throw で例外をスローし、try-catch ブロックで自分でキャッチすることを考えることができる唯一の有効な使用法です。ただし、代わりに標準の if ブロックを使用する必要があります。誰かが例外をスローしてから自分でキャッチする必要がある理由がわかりません。

2 番目の方法は、特に例外をスローするメソッドの呼び出し元が外部モジュールである場合、より標準的です。これは、実際に何か問題が発生したことを知らせる方法です。例外を処理するのは呼び出し元の責任です。

于 2009-02-09T14:56:05.973 に答える
2

手動で例外をスローする場合は、処理が必要なエラーが発生していることは明らかです。新しい例外をスローしてキャッチし、すぐにエラーを処理するのではなく、単にエラーを処理しないのはなぜですか? ユーザー (およびプロセッサ) は、例外を生成してキャッチするすべての作業を行う必要はありません。また、例外により、コードの読み取りとデバッグが難しくなります。

次の場合は、エラーをただちに処理するのではなく、例外をスローします。

  • メソッドを呼び出したコードなど、他のコードでエラーを処理する必要があります。たとえば、コードが UI コードでない場合、おそらくウィンドウを生成すべきではありません。これはあなたの方法#2です。

  • try、catch、finally ブロックを利用できます。この方法でよりクリーンなコードを作成できる可能性はありますが、単純な if ステートメントを使用すると、90% の確率でコードが読みやすくなると思います。

于 2009-02-09T15:08:03.793 に答える
1

制御フローの例外の使用については、Joshua Bloch 著の「Effective Java, 2nd Edition 」の項目 57 で具体的に説明されています。

項目 57: 例外は例外的な状況にのみ使用する

...例外は、その名前が示すように、例外的な条件にのみ使用されます。通常の制御フローには使用しないでください。[イタリック鉱山]

したがって、例外を使用してフローを制御することは確かに「機能」しますが、お勧めしません。

于 2009-02-09T16:48:24.410 に答える
1

私の経験では、最初の方法を使用すると、機能とエラー処理が混同されているため、コードがすぐに読めなくなります。ただし、try{}catch{} finaly {} がある場合には意味があります。たとえば、常に接続を閉じたいファイル処理やデータベース処理などです

try{ //do something
}catch(Exception ex){
//log
}finally{
//connection.close
}

それ以外の場合は、2 番目のオプションを使用します。これは、エラー処理ルーチンを集中化し、ビジネス ロジック自体を実装するコードの可読性を維持するためです。

于 2009-02-09T14:56:24.053 に答える
1

私の意見では、書き込みブロックには、同じメソッド内でキャッチされる「新しいスロー」を含めないでください。例外をスローすると、「処理できない状況に遭遇しました。他の誰かが処理する必要があります」と言っているのです。「throw new」を使用するメソッドは、未チェックの例外を作成してスローするか、メソッド シグネチャでチェック済みの例外を宣言する必要があります。

例外をスローする可能性のあるサードパーティのクラスを使用している場合、例外が発生した場合に実際に状況を処理できるのであれば、メソッドに try/catch ブロックが必要です。それ以外の場合は、可能な別のクラスに委ねる必要があります。

独自の例外を作成せず、同じメソッドでキャッチします。

于 2009-02-09T14:58:33.223 に答える
0

それが無意味に見える理由 (同じメソッドでのスローとキャッチ) は、フロー制御に例外を使用するシナリオになるためです。例外がスローされる条件を特定するのに十分なデータが既にある場合は、その情報を使用して代わりに条件を使用できます。

下記参照:

1)同じメソッドで例外をスローしてキャッチする(間違っている

public void method() { 
    try {    
        workA...
        workA...
        workA...
        workA...    
        if( conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) { 
            throw new IllegalStateException("No the rigth time" );
        }
        workB...
        workB...
        workB...
        workB...
    } catch( IllegalStateException iee ) { 
        System.out.println( "Skiped workB...");
    }
    workC....
    workC....
    workC....
    workC....
}

このシナリオでは、セクション「workB」をスキップするために例外スローが使用されます。

これは次のようにするとよいでしょう:

2) 条件を使用してフローを制御する ()

public void method() { 
    workA...
    workA...
    workA...
    workA...    
    if( !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) ) { 
        //throw new IllegalStateException("No the rigth time" );
        workB...
        workB...
        workB...
        workB...

    }
    workC....
    workC....
    workC....
    workC....
}

次に、条件をリファクタリングできます。

    if( !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) ) { 

為に

    if( canProceedWithWorkB() ) {

次のように実装されます。

  boolean canProceedWithWorkB() {  
      return !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() );
  } 
于 2009-02-09T16:31:13.077 に答える