2017-11-16 20 views
5

は..私はJavaでの例外のラッピングは、ビット「醜い」が見つかり:Java例外のラッピング:悪い練習ですか?例外処理を書くための唯一の方法がありますPHPの世界から来る

public void exampleOneException(String input) throws MyBusinessException { 
    try { 
     // do something 
    } catch (NumberFormatException e) { 
     throw new MyBusinessException("Error...", e); 
    } 
} 

私が代わりにこのスタイルを使用することを好む:

public void exampleTwoException() { 
    try { 
     // do something 
    } catch (MyBusinessException e) { 
     log.error("Error...: " + e); 
    } catch (NumberFormatException e) { 
     log.error("Error...: " + e); 
    } 
} 

例外処理に関するこれらのアプローチには、相違点やベストプラクティスがありますか?

+0

'exampleOneException'を呼び出すメソッドは、' MyBusinessException'を捕捉し、それ自身の要件に従って処理できます。 'exampleTwoException'を呼び出すメソッドは何かが間違っていたことを知る方法がありません。 – khelwood

+2

これらは根本的に異なることをしています。使用するアプローチは、エラーにどのように対応するかによって異なります。それらをローカルにロギングしたり、転送したり、エラーが発生したときの動作を変更する専用のビジネスロジックを使用することができます。 –

+1

2つのコードスニペットは同じことをしていません。 1つは、もう一方の例外で例外を再投げているだけです。 –

答えて

5

これらは、2つの異なるシナリオで有効なアプローチです。

最初のシナリオでは、このメソッドは例外についてインテリジェントな処理を行うことはできませんが、それを上方向に「レポート」する必要があります。こうすることで、呼び出し側は例外をキャッチして何をするかを決めることができます(例えば、フローをキャンセルする、ユーザにメッセージをポップする、ログするなど)

2番目のシナリオでは、それは呼び出し元からの失敗を効果的に隠しています。このタイプの処理は、操作が成功したかどうかを呼び出し元が実際に気にしない場合に便利です。

+1

操作が成功することが確実であれば、catch節には何も書き込むこともできません。それは悪いプログラミングと見なされますが、人々が怠け者だから単純に広く使われています^^ –

1

私はNumberFormatExceptionMyBusinessExceptionの両方が有用であるが、異なる場合があると言います。

通常、クラス階層の異なるレベルに表示されます。たとえば、NumberFormatExceptionは下位レベルの例外であり、そのユーザーには回復の権限がない場合は上位レベル(ユーザーインターフェイスなど)に公開したくない場合がありますそれから。この場合、単にMyBusinessExceptionを投げて、前のステップで何かがひどく供給されたか、何らかの内部処理エラーが発生し、プロセスを再開する必要があるなどの情報メッセージを表示する方がよりエレガントです。

一方、関数が中間レベル(APIなど)で使用されていて、開発者が例外的な動作から回復する手段を持っている場合は、プログラムで扱うことができるため、NumberFormatExceptionが便利です。アプリケーションのフローは、中断を最小限にして続行することができます(たとえば、デフォルトの有効な番号を指定するなど)。あるいは、これは修正すべきコードの欠陥/バグを示すことができます。

例外を使用する際のベストプラクティスの方法については、Effective Java by Joshua BlochからItem 61 - Throw exceptions appropriate to the abstractionをお読みください。

3

第1の例は、一般的に、より良いアプローチと考えられる。

またMyBusinessExceptionラッピングNumberFormatExceptionであると考えてはならないのではなく、NumberFormatExceptionMyBusinessException原因です。

インターフェイスが公開されている場合、例外が適切である必要があります。インターフェイスの呼び出し元は、実装の詳細を知っている必要はありません。 NumberFormatExceptionexampleOneExceptionを呼び出すときにエラーのタイプとして真に意味を持たない限り、より適切な例外に変換する必要があります。

より具体的な例は、インターフェイスのユーザーが実装の詳細(コンパイル時でさえも知られていないかもしれない)に対処する必要がない、異なる実装を一般的に含む。

interface MyRepository { 
    Object read(int id) throws ObjectNotFoundException; 
} 

// a sql backed repository 
class JdbcRepository implements MyRepository { 
    public Object read(int id) throws ObjectNotFoundException { 
     try { ... } 
     catch (SQLException ex) { 
      throw new ObjectNotFoundException(ex); 
     } 
    } 
} 

// a file backed repository 
class FileRepository implements MyRepository { 
    public Object read(int id) throws ObjectNotFoundException { 
     try { ... } 
     catch (FileNotFoundException ex) { 
      throw new ObjectNotFoundException(ex) 
     } 
    } 
} 

インターフェイスが返すエラーの種類を宣言しているため、そのインターフェイスのクライアントは一貫性と合理性があります。 FileNotFoundExceptionSQLExceptionを処理するコードを追加すると、実際の実装はどちらか一方でもどちらでもないことは素晴らしいことではありません。

FileRepositoryの実装に複数の場所があり、FileNotFoundExceptionを投げる可能性がある場合を考えます。それは、それぞれのすべてが、オブジェクトが見つからないことを暗示していますか?

オプション2を考慮する場合は、catchブロックが発生したエラーの影響が軽減されていることを効果的に示していることを認識することが重要です。そこはチェック例外が合理的に無視され例がありますが、簡単な

try { ... } 
catch (SomeException ex) { 
    log.error("caught some exception", ex); 
} 

が実際に例外の影響を考慮していない開発者の結果である、またはコードが含まれている必要があることをはるかに可能性がありますFIXME

これは、catch (Exception ex)、または妥当性のないcatch (Throwable ex)が表示されている場合にさらに当てはまります。

最後に、新しい実装を処理するために別のキャッチブロックを追加する必要があるすべての場所を見つけるアプリケーションを掘り下げたいと思うでしょうか?おそらくそれは...あなたが右方向に駆動されていないクリーンな固体コードの観点から抽象

0

に適切な

必ず投げる例外catch (Exception ex)の原因です。
最初に、メソッドのヘッダーによってすでにスローされているExceptionにtry/catchを使用する必要はありません。だからあなたの最初のケースでは、コードは以下のようになります:

public void exampleOneException(String input) throws MyBusinessException { 
    // do something 
} 

これはそれですか? 上記の場合、MyBusinessExceptionが発生した場合、例外は飲み込まれるため、ユーザーは何が起こったかを決して見られません。これが起こることを望むなら、これはあなたのベストプラクティスです。

2番目のケースはクリアです。あなたは2つの異なる例外をキャッチし、あなたはそれらを(対処することによって) 扱います。

したがって、2つの異なるケースのベストプラクティスは、達成したいことによって異なります。美しさに関しては、これは完全に主観的です。

+0

私はfinallyを使う必要がある時にtry/catchが必要です:Javaガベージコレクタに頼るのではなく、 – numediaweb

+0

説明:例外を処理したい場合は、try/catchが必要です。伝播や処理を気にしないなら、メソッドのヘッダに 'throws'を使うことができます。 「最終的に」を使用することは、取り扱いの意図を前提とする。 –

+0

もし我々がコードの質を気にして、lintingライブラリ(sonarlint)を使うなら、最終的には "良い習慣"を使うか、linterにエラーを表示させます: "リソースは閉じなければなりません" ..しかしそれは別の話題です。 – numediaweb

関連する問題