コードは次のとおりです。
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;
}
このプログラムは正常に動作しています。私はそれが再設計されるべきだと思うが、どうやって?
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;
}
メソッドから例外をスローしている場合、なぜそれをキャッチするのですか? 「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;
}
}
意図的に例外をスローしてから直接キャッチするのは適切ではないようです。このように再設計することができます。
は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;
}
あなたはそのトライ/キャッチのポイントを見逃しているのではないかと思います。コードは例外システムを使用して、例外メッセージを呼び出し元にバブルしています。これは、あなたが見ている「スロー」だけではなく、ネストされた呼び出しスタックの奥深くにある可能性があります。
つまり、サンプルコードの「スロー」宣言はこのメカニズムを利用してクライアントにメッセージを配信していますが、ほぼ確実にtry/catchの主な対象ユーザーではありません。 (また、このメッセージを配信するためのずさんな、ちょっと安い方法です-混乱を招く可能性があります)
とにかく、この戻り値は素晴らしいアイデアではありません。なぜなら、例外には多くの場合、メッセージがなく、再ラップできるからです。例外メッセージはこれに最適なツールではありませんが、このような高いレベルで例外を処理することは依然として良い考えです。
私のポイントは、このコードをリファクタリングする場合は、コードベースのどこか(少なくともメッセージ処理中に呼び出される場所)にスローされる可能性のあるランタイム例外を必ず探してください。そして、おそらくキャッチ/リターンメッセージを予期しないランタイム例外がポップアップした場合に備えて、すべてをキャッチします。応答のメッセージとしてエラー「メッセージ」を返す必要はありません-代わりに「この時点でリクエストを処理できませんでした」というちょっとした質問かもしれませんが、必ずスタックトレースをログにダンプしてください。あなたは現在それを捨てています。
何よりもまず、作業メソッドをリファクタリングするときは、特に手動リファクタリングを実行している場合は、注意してください。ただし、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:例外を無視しないでください。
次のリンクをご覧ください。
例外メカニズムには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;
}