web-dev-qa-db-ja.com

if-elseブロックで例外をスローする必要がありますか?

コードは次のとおりです。

public Response getABC(Request request) throws Exception {
    Response res = new Response();
    try {
        if (request.someProperty == 1) {
            // business logic
        } else {
           throw new Exception("xxxx");
        }
    } catch (Exception e) {
        res.setMessage(e.getMessage); // I think this is weird
    }
    return res;
}

このプログラムは正常に動作しています。私はそれが再設計されるべきだと思うが、どうやって?

28
Lauda Wang

Catchブロックが別の例外をスローしない限り、tryブロックで例外をスローしてすぐにキャッチすることは意味がありません。

あなたのコードはこのようにもっと理にかなっています:

public Response getABC(Request request) {
    Response res = new Response();
    if (request.someProperty == 1) {
        // business logic
    } else {
        res.setMessage("xxxx");
    }
    return res;
}

(条件がtrueのときに実行される)ビジネスロジックが例外をスローする可能性がある場合にのみ、try-catchブロックが必要です。

例外をキャッチしない場合(呼び出し側が処理する必要があることを意味します)、else句なしで実行できます。

public Response getABC(Request request) throws Exception {
    if (request.someProperty != 1) {
        throw new Exception("xxxx");
    }

    Response res = new Response();
    // business logic
    return res;
}
44
Eran

メソッドから例外をスローしている場合、なぜそれをキャッチするのですか? 「xxxx」メッセージで応答を返すか、このメソッドの呼び出し元に例外をスローして処理します。

public Response getABC(Request requst) {
    Response res = new Response();
        if(request.someProperty == 1){
            //business logic
        else{
           res.setMessage("xxxx");
        }
    }
    return res;
}

OR

public Response getABC(Request requst) throw Excetpions {
    Response res = new Response();
        if(request.someProperty == 1){
            //business logic
        else{
           throw new Exception("xxxx");
        }
    return res;
}


public void someMethod(Request request) {
    try {
        Response r = getABC(request);
    } catch (Exception e) {
        //LOG exception or return response with error message
        Response response = new Response();
        response.setMessage("xxxx");
        retunr response;
    }

}
16
mkjh

意図的に例外をスローしてから直接キャッチするのは適切ではないようです。このように再設計することができます。
throw new Exception("xxxx");res.setMessage("xxxx");で変更できます。
そして、ビジネスロジック内で発生する可能性のある例外をキャッチするために、キャッチ例外部分を保持できます。

public Response getABC(Request requst) {
  Response res = new Response();
  try{
      if(request.someProperty == 1){
          //business logic
      else{
         res.setMessage("xxxx");
      }
  }catch(Exception e){
      res.setMessage(e.getMessage);
  }
  return res;
}
9
m fauzan abdi

あなたはそのトライ/キャッチのポイントを見逃しているのではないかと思います。コードは例外システムを使用して、例外メッセージを呼び出し元にバブルしています。これは、あなたが見ている「スロー」だけではなく、ネストされた呼び出しスタックの奥深くにある可能性があります。

つまり、サンプルコードの「スロー」宣言はこのメカニズムを利用してクライアントにメッセージを配信していますが、ほぼ確実にtry/catchの主な対象ユーザーではありません。 (また、このメッセージを配信するためのずさんな、ちょっと安い方法です-混乱を招く可能性があります)

とにかく、この戻り値は素晴らしいアイデアではありません。なぜなら、例外には多くの場合、メッセージがなく、再ラップできるからです。例外メッセージはこれに最適なツールではありませんが、このような高いレベルで例外を処理することは依然として良い考えです。

私のポイントは、このコードをリファクタリングする場合は、コードベースのどこか(少なくともメッセージ処理中に呼び出される場所)にスローされる可能性のあるランタイム例外を必ず探してください。そして、おそらくキャッチ/リターンメッセージを予期しないランタイム例外がポップアップした場合に備えて、すべてをキャッチします。応答のメッセージとしてエラー「メッセージ」を返す必要はありません-代わりに「この時点でリクエストを処理できませんでした」というちょっとした質問かもしれませんが、必ずスタックトレースをログにダンプしてください。あなたは現在それを捨てています。

7
Bill K

何よりもまず、作業メソッドをリファクタリングするときは、特に手動リファクタリングを実行している場合は、注意してください。ただし、messageを保持する変数を導入することは、設計を変更する1つの方法かもしれません。

public Response getABC(Request requst) throw Excetpions {
    String message = "";
    try{
        if(request.someProperty == 1){
            //business logic
        else{
           message = "xxxx";
        }
    }catch(Exception e){
        message = e.getMessage();
    }
    Response res = new Response();
    res.setMessage(message);
    return res;
}

business logicは、成功したときに独自の戻り値を返すという前提です。

既にChecked Exceptionをスローしたときにtry/catchステートメントを使用したのはなぜですか?

チェック済み例外は通常、C++やJavaなどの一部の言語で使用されますが、Kotlinなどの新しい言語では使用されません。個人的に使用を制限しています。

たとえば、次のようなクラスがあります。

class ApiService{
    Response getSomething() throw Exception(); 
} 

クリーンで読みやすいと感じますが、例外処理メカニズムの有用性を損ないます。実際、getSomething()はチェック例外をスローしませんが、それでも動作する必要がありますか?これは、ApiServiceの上流にunpredictableまたはunpreventableこのようなエラー。そして、あなたが本当にそれを扱う方法を知っているなら、先に進み、以下の例のようなものを使用してください、そうでなければ、未チェックのExceptionで十分です。

public Response getSomething(Request req) throws Exception{
    if (req.someProperty == 1) {
        Response res = new Response();
        // logic 
    } else {
        thows Exception("Some messages go here")
    }
}

この方法で行うことをお勧めします。

public Response getSomething(Request req){
if (req.someProperty == 1) {
        Response res = new Response();
        // logic 
        return res;
    } else {
        return ErrorResponse("error message"); // or throw RuntimeException here if you want to
    }
}

より多くの洞察のために、私が前に言及したKotlinは多くの理由のためにサポートされていませんチェックされた例外

以下は、JDKクラスによって実装されるStringBuilderのサンプルインターフェイスです。

Appendable append(CharSequence csq) throws IOException;

この署名は何と言っていますか?文字列を何か(StringBuilder、ある種のログ、コンソールなど)に追加するたびに、それらのIOExceptionsをキャッチする必要があると書かれています。どうして? IOを実行している可能性があるため(ライターはAppendableも実装します)…その結果、この種のコードが至る所で発生します。

try {
    log.append(message)
}
catch (IOException e) {
    // Must be safe
}

これはダメです。Effective Java、3rd Edition、Item 77:例外を無視しないでください。

次のリンクをご覧ください。

5
nhp

例外メカニズムには3つの目的があります。

  1. すぐに通常のプログラムフローを無効にし、適切なcatch-blockが見つかるまでコールスタックを遡ります。
  2. 例外タイプ、メッセージ、およびキャッチブロックコードがアクションのコースを決定するために使用できるオプションの追加フィールドの形式でコンテキストを提供します。
  3. フォレンシック分析を行うためにプログラマが見るためのスタックトレース。 (これは以前は非常に高価でした)。

これは、メカニズムが持つべき多くの機能です。プログラムをできるだけシンプルに保つために、将来のメンテナーのために本当にが必要な場合にのみこのメカニズムを使用すべきです。

コード例では、throwステートメントは何かが間違っていることを示す非常に深刻なものであり、コードはどこかでこの緊急事態を処理することが期待されます。プログラムの残りの部分を読む前に、何がうまくいかなかったか、そしてそれがどれほど深刻かを理解する必要があります。ここでは、単なる文字列の空想的な戻り値であり、頭を掻いて「なぜこれが必要だったのだろう」と思うでしょう。そして、その余分な努力はよりよく費やされたかもしれません。

したがって、このコードは可能な限り優れていませんが、完全なテストを行う時間がある場合にのみ変更します。プログラムフローを変更すると、微妙なエラーが発生する可能性があるため、何かを修正する必要がある場合は、変更を記憶しておく必要があります。

障害時にJVMから返される特定の例外メッセージを取得する場合も同じです。その場合、catchブロックでメソッドgetMessage()またはprintStackTrace()でtry-catchを使用できます。そのため、次のようにコードを変更できます。

public Response getABC(Request request) throws Exception {
    Response res = new Response();
    try {
        if (request.someProperty == 1) {
            // business logic
        } 
    } catch (Exception e) {
        res.setMessage(e.getMessage); 
    }
    return res;
}
3
Deepak Bhavale