Java例外を処理する9つのベストプラクティス
8653 ワード
Javaでの例外処理は簡単なトピックではありません.初心者は理解しにくいことに気づき、経験のある開発者も何時間もかけて、どのような異常を投げ出したり処理したりするべきかを議論することができます.
これは、多くの開発チームが独自のルールを持っている理由です.チームの初心者であれば、これらのルールがあなたが以前使っていたルールとどのように異なるかに驚くかもしれません.
それでも、多くのチームはいくつかのベストプラクティスを使用しています.以下は、例外処理の入門や改善に役立つ9つの最も重要な内容です.
1.finallyブロックでのリソースのクリーンアップまたはTry-With-resource文の使用
tryブロックでのリソースの使用は頻繁です.例えば、 InputStream ,を選択してもアクセスできます.これらの場合の一般的なエラーの1つは、tryブロックの終了時にリソースを閉じることです.
問題は異常を投げ出さない限り、この方法は完全に正常のようだ.tryブロック内のすべての文が実行され、リソースが閉じられます.
しかし、tryブロックを追加したのは理由があります.異常を投げ出す可能性のある方法を1つ以上呼び出したり、自分で異常を投げ出したりします.これはtryブロックの最後に到達できない可能性があることを意味します.そのため、リソースを閉じることはありません.
したがって、finallyブロックにすべてのクリーンアップコードを入れるか、try-with-resource文を使用する必要があります.
Finallyブロックの使用
finallyブロックは、tryブロックの最後の行に比べて常に実行されます.これは、tryブロックが正常に実行された後、またはcatchブロックで例外が処理された後に発生することができる.したがって、開いているすべてのリソースをクリーンアップすることができます.
Java 7のTry-With-resource
もう1つの選択肢はtry-with-resource文で、私はこれについてもっと詳しく説明しました.
リソースが実装された場合 AutoCloseable インタフェースを使用します.これが多くのJava標準リソースが行っていることです.try句でリソースを開くと、tryブロックの実行後に自動的に閉じたり、例外を処理したりします.
2.特定異常
放出された異常は具体的であればあるほどよい.コードが分からない同僚や、数ヶ月後に方法を呼び出して異常を処理する必要がある可能性があることを覚えておいてください.
そのため、できるだけ多くの情報を提供してください.これにより、APIがより理解しやすくなります.そのため、あなたの方法の呼び出し者は異常や 追加の検査で避ける .
そのため、常にあなたの異常イベントに最適なクラスを見つけようとします.例えば、投げ出すなどです. NumberFormatException ではなく IllegalArgumentException .非特定の異常を投げ出すことを避ける.
3.あなたが宣言した異常を記録する
メソッド署名でいつでも、 Javadocに記録する .これは、以前のベストプラクティスと同じ目標を持っています.呼び出し者にできるだけ多くの情報を提供し、異常を回避または処理できるようにします.
したがって、Javadocに@throws宣言を追加し、例外の原因となる可能性があることを確認してください.
4.記述情報を用いて異常を放出する
このようなベストプラクティスの背後にある考えは、前の2つの実践に似ている.しかし、今回は呼び出し元にメソッドに関する情報を提供しません.ログ・ファイルまたは監視ツールで例外が投げ出されたときに何が起こったのかを知る必要がある人は、例外のメッセージを読み取ります.
したがって、問題をできるだけ正確に記述し、異常イベントを理解するために最も関連する情報を提供する必要があります.
私の意味を誤解しないでください.君は文字を書くべきではない.しかし、この例外の原因を1~2つの短い文で説明する必要があります.これにより、運用チームが問題の深刻さを理解し、サービスイベントをより簡単に分析することができます.
特定の例外が投げ出されると、そのクラス名はそのエラーを記述している可能性が高い.そのため、他の情報を大量に提供する必要はありません.良い例はNumberFormatExceptionです.クラスjava.lang.Longのコンストラクション関数によって放出され、Stringパラメータを誤ったフォーマットで指定します.
NumberFormatExceptionクラスの名前は、問題のタイプを示しています.メッセージは、問題を引き起こす入力文字列を指定するだけです.例外クラスの名前に表現力がない場合は、メッセージに必要な情報を指定する必要があります.
17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"
5.最も具体的な異常を優先的にキャプチャする
ほとんどのIDEは、このベストプラクティスを実現するのに役立ちます.あまり具体的でない例外を最初にキャプチャしようとすると、アクセスできないコードブロックが表示されます.
問題は、異常に一致する最初のcatchブロックのみが実行されることです.したがって、IllegalArgumentExceptionを最初に取得すると、IllegalArgumentExceptionのサブクラスであるため、より具体的なNumber FormatExceptionを処理すべきcatchブロックには到達しません.
常に最も特定の例外クラスを優先的にキャプチャし、リストの末尾にあまり特定のcatchブロックを追加します.
このようなtry-catch文の例は、次のコードセグメントで参照できます.最初のcatchブロックはすべてのNumberFormatExceptionを処理し、2番目の処理はすべてNumberFormatExceptionではないIllegalArgumentException異常を処理します.
6.Don’t Catch Throwable
Throwable は、すべての例外とエラーのスーパークラスです.catchの句で使用することができますが、あなたは永遠にこのようにするべきではありません!
catch句でThrowableを使用すると、すべての例外がキャプチャされます.また、すべてのエラーがキャプチャされます.JVMは、アプリケーションが処理できない重大な問題を示すエラーを投げ出します.典型的な例は OutOfMemoryError または StackOverflowError .どちらもアプリケーションが制御できない場合に起因し、処理できません.
だから、Throwableを捕まえないほうがいいです.特別な状況にあると完全に確定しない限り、エラーを処理することができます.
7.Don’t Ignore Exceptions
使用例第1部のみで実行されたエラーレポートを分析したことがありますか?
これは通常、無視された異常によって引き起こされる.開発者は、処理または記録しないcatchブロックを決して投げ出されずに追加しないことを非常に確信している可能性があります.このコードブロックを見つけると、有名な「This will never happen」のコメントを見つけることができます.
起こり得ない問題を分析しているかもしれません
だから、異常を無視しないでください.コードが将来どのように変化するか分かりません.問題が発生することを認識せずに、例外イベントをブロックする検証を削除する人もいるかもしれません.または、例外を投げ出すコードが変更され、同じクラスの複数の例外が投げ出され、呼び出しコードがこれらの例外をすべて阻止することはありません.
少なくとも1つのログメッセージを書いて、不思議なことが起こったばかりで、誰かがそれをチェックする必要があることを伝えるべきです.
8.Don’t Log and Throw
これは、このリストで最も無視される最善の方法かもしれません.多くのコードクリップ、catch、log、再throw異常のライブラリを見つけることができます.
異常が発生した場合に異常を記録すると、直接的に感じられ、呼び出し者が適切に処理できるように再放出される可能性があります.しかし、同じ例外に複数のエラーメッセージが書かれます.
他のメッセージにも情報は追加されません.ベストプラクティス#4で説明したように、例外メッセージは例外イベントを記述する必要があります.スタックトラッキングは、異常なクラス、方法、行を投げ出すことを示します.
追加情報が必要な場合は、例外をキャプチャし、カスタム例外にパッケージします.ただし、ベストプラクティス9に必ず従ってください.
したがって、それを処理したい場合は、例外のみをキャプチャします.そうでなければ、メソッド署名で指定し、呼び出し元に処理させます.
9.消費がない場合の包装異常
標準例外をキャプチャし、カスタム例外にパッケージすると良い場合があります.このような例外の典型的な例は、アプリケーションまたはフレームワーク固有のビジネス例外です.これにより、他の情報を追加したり、例外クラスの特殊な処理を実行したりすることができます.
この操作を実行する場合は、元の例外がcauseに設定されていることを確認します.この異常クラスは、パラメータとして特定の構造方法を受け入れるThrowableを提供する.そうしないと、元の例外のスタック追跡とメッセージが失われ、例外を引き起こす例外イベントの解析が困難になります.
まとめ
見たように、異常を投げ出したり捕獲したりするときは、いろいろなことを考えなければなりません.これらのほとんどは、コードの可読性またはAPIの可用性を向上させることを目的としています.
異常は通常、エラー処理メカニズムと通信媒体を同時に行う.したがって、共通の概念を理解し、同じ方法で使用できるように、同僚と適用するベストプラクティスとルールを議論する必要があります.
Javaとビッグデータを学ぶ友达を歓迎してjavaアーキテクチャの交流に参加します:855835163加群リンク:https://jq.qq.com/?_wv=1027&k=5 dPqXGI群内で無料のアーキテクチャ資料を提供するほか、Javaエンジニアリング、高性能と分布式、高性能、深入浅出がある.高アーキテクチャ.パフォーマンスチューニング、Spring、MyBatis、Nettyソース分析、ビッグデータなど複数の知識ポイントの高級進級乾物の無料生放送説明 一緒に勉強してもいいですよ
これは、多くの開発チームが独自のルールを持っている理由です.チームの初心者であれば、これらのルールがあなたが以前使っていたルールとどのように異なるかに驚くかもしれません.
それでも、多くのチームはいくつかのベストプラクティスを使用しています.以下は、例外処理の入門や改善に役立つ9つの最も重要な内容です.
1.finallyブロックでのリソースのクリーンアップまたはTry-With-resource文の使用
tryブロックでのリソースの使用は頻繁です.例えば、 InputStream ,を選択してもアクセスできます.これらの場合の一般的なエラーの1つは、tryブロックの終了時にリソースを閉じることです.
public void doNotCloseResourceInTry() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
// do NOT do this
inputStream.close();
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
問題は異常を投げ出さない限り、この方法は完全に正常のようだ.tryブロック内のすべての文が実行され、リソースが閉じられます.
しかし、tryブロックを追加したのは理由があります.異常を投げ出す可能性のある方法を1つ以上呼び出したり、自分で異常を投げ出したりします.これはtryブロックの最後に到達できない可能性があることを意味します.そのため、リソースを閉じることはありません.
したがって、finallyブロックにすべてのクリーンアップコードを入れるか、try-with-resource文を使用する必要があります.
Finallyブロックの使用
finallyブロックは、tryブロックの最後の行に比べて常に実行されます.これは、tryブロックが正常に実行された後、またはcatchブロックで例外が処理された後に発生することができる.したがって、開いているすべてのリソースをクリーンアップすることができます.
public void closeResourceInFinally() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e);
}
}
}
}
Java 7のTry-With-resource
もう1つの選択肢はtry-with-resource文で、私はこれについてもっと詳しく説明しました.
リソースが実装された場合 AutoCloseable インタフェースを使用します.これが多くのJava標準リソースが行っていることです.try句でリソースを開くと、tryブロックの実行後に自動的に閉じたり、例外を処理したりします.
public void automaticallyCloseResource() {
File file = new File("./tmp.txt");
try (FileInputStream inputStream = new FileInputStream(file);) {
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
2.特定異常
放出された異常は具体的であればあるほどよい.コードが分からない同僚や、数ヶ月後に方法を呼び出して異常を処理する必要がある可能性があることを覚えておいてください.
そのため、できるだけ多くの情報を提供してください.これにより、APIがより理解しやすくなります.そのため、あなたの方法の呼び出し者は異常や 追加の検査で避ける .
そのため、常にあなたの異常イベントに最適なクラスを見つけようとします.例えば、投げ出すなどです. NumberFormatException ではなく IllegalArgumentException .非特定の異常を投げ出すことを避ける.
public void doNotDoThis() throws Exception {
...
}
public void doThis() throws NumberFormatException {
...
}
3.あなたが宣言した異常を記録する
メソッド署名でいつでも、 Javadocに記録する .これは、以前のベストプラクティスと同じ目標を持っています.呼び出し者にできるだけ多くの情報を提供し、異常を回避または処理できるようにします.
したがって、Javadocに@throws宣言を追加し、例外の原因となる可能性があることを確認してください.
/**
* This method does something extremely useful ...
*
* @param input
* @throws MyBusinessException if ... happens
*/
public void doSomething(String input) throws MyBusinessException {
...
}
4.記述情報を用いて異常を放出する
このようなベストプラクティスの背後にある考えは、前の2つの実践に似ている.しかし、今回は呼び出し元にメソッドに関する情報を提供しません.ログ・ファイルまたは監視ツールで例外が投げ出されたときに何が起こったのかを知る必要がある人は、例外のメッセージを読み取ります.
したがって、問題をできるだけ正確に記述し、異常イベントを理解するために最も関連する情報を提供する必要があります.
私の意味を誤解しないでください.君は文字を書くべきではない.しかし、この例外の原因を1~2つの短い文で説明する必要があります.これにより、運用チームが問題の深刻さを理解し、サービスイベントをより簡単に分析することができます.
特定の例外が投げ出されると、そのクラス名はそのエラーを記述している可能性が高い.そのため、他の情報を大量に提供する必要はありません.良い例はNumberFormatExceptionです.クラスjava.lang.Longのコンストラクション関数によって放出され、Stringパラメータを誤ったフォーマットで指定します.
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
}
NumberFormatExceptionクラスの名前は、問題のタイプを示しています.メッセージは、問題を引き起こす入力文字列を指定するだけです.例外クラスの名前に表現力がない場合は、メッセージに必要な情報を指定する必要があります.
17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"
5.最も具体的な異常を優先的にキャプチャする
ほとんどのIDEは、このベストプラクティスを実現するのに役立ちます.あまり具体的でない例外を最初にキャプチャしようとすると、アクセスできないコードブロックが表示されます.
問題は、異常に一致する最初のcatchブロックのみが実行されることです.したがって、IllegalArgumentExceptionを最初に取得すると、IllegalArgumentExceptionのサブクラスであるため、より具体的なNumber FormatExceptionを処理すべきcatchブロックには到達しません.
常に最も特定の例外クラスを優先的にキャプチャし、リストの末尾にあまり特定のcatchブロックを追加します.
このようなtry-catch文の例は、次のコードセグメントで参照できます.最初のcatchブロックはすべてのNumberFormatExceptionを処理し、2番目の処理はすべてNumberFormatExceptionではないIllegalArgumentException異常を処理します.
public void catchMostSpecificExceptionFirst() {
try {
doSomething("A message");
} catch (NumberFormatException e) {
log.error(e);
} catch (IllegalArgumentException e) {
log.error(e)
}
}
6.Don’t Catch Throwable
Throwable は、すべての例外とエラーのスーパークラスです.catchの句で使用することができますが、あなたは永遠にこのようにするべきではありません!
catch句でThrowableを使用すると、すべての例外がキャプチャされます.また、すべてのエラーがキャプチャされます.JVMは、アプリケーションが処理できない重大な問題を示すエラーを投げ出します.典型的な例は OutOfMemoryError または StackOverflowError .どちらもアプリケーションが制御できない場合に起因し、処理できません.
だから、Throwableを捕まえないほうがいいです.特別な状況にあると完全に確定しない限り、エラーを処理することができます.
public void doNotCatchThrowable() {
try {
// do something
} catch (Throwable t) {
// don't do this!
}
}
7.Don’t Ignore Exceptions
使用例第1部のみで実行されたエラーレポートを分析したことがありますか?
これは通常、無視された異常によって引き起こされる.開発者は、処理または記録しないcatchブロックを決して投げ出されずに追加しないことを非常に確信している可能性があります.このコードブロックを見つけると、有名な「This will never happen」のコメントを見つけることができます.
public void doNotIgnoreExceptions() {
try {
// do something
} catch (NumberFormatException e) {
// this will never happen
}
}
起こり得ない問題を分析しているかもしれません
だから、異常を無視しないでください.コードが将来どのように変化するか分かりません.問題が発生することを認識せずに、例外イベントをブロックする検証を削除する人もいるかもしれません.または、例外を投げ出すコードが変更され、同じクラスの複数の例外が投げ出され、呼び出しコードがこれらの例外をすべて阻止することはありません.
少なくとも1つのログメッセージを書いて、不思議なことが起こったばかりで、誰かがそれをチェックする必要があることを伝えるべきです.
public void logAnException() {
try {
// do something
} catch (NumberFormatException e) {
log.error("This should never happen: " + e);
}
}
8.Don’t Log and Throw
これは、このリストで最も無視される最善の方法かもしれません.多くのコードクリップ、catch、log、再throw異常のライブラリを見つけることができます.
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
throw e;
}
異常が発生した場合に異常を記録すると、直接的に感じられ、呼び出し者が適切に処理できるように再放出される可能性があります.しかし、同じ例外に複数のエラーメッセージが書かれます.
17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
他のメッセージにも情報は追加されません.ベストプラクティス#4で説明したように、例外メッセージは例外イベントを記述する必要があります.スタックトラッキングは、異常なクラス、方法、行を投げ出すことを示します.
追加情報が必要な場合は、例外をキャプチャし、カスタム例外にパッケージします.ただし、ベストプラクティス9に必ず従ってください.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
したがって、それを処理したい場合は、例外のみをキャプチャします.そうでなければ、メソッド署名で指定し、呼び出し元に処理させます.
9.消費がない場合の包装異常
標準例外をキャプチャし、カスタム例外にパッケージすると良い場合があります.このような例外の典型的な例は、アプリケーションまたはフレームワーク固有のビジネス例外です.これにより、他の情報を追加したり、例外クラスの特殊な処理を実行したりすることができます.
この操作を実行する場合は、元の例外がcauseに設定されていることを確認します.この異常クラスは、パラメータとして特定の構造方法を受け入れるThrowableを提供する.そうしないと、元の例外のスタック追跡とメッセージが失われ、例外を引き起こす例外イベントの解析が困難になります.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
まとめ
見たように、異常を投げ出したり捕獲したりするときは、いろいろなことを考えなければなりません.これらのほとんどは、コードの可読性またはAPIの可用性を向上させることを目的としています.
異常は通常、エラー処理メカニズムと通信媒体を同時に行う.したがって、共通の概念を理解し、同じ方法で使用できるように、同僚と適用するベストプラクティスとルールを議論する必要があります.
Javaとビッグデータを学ぶ友达を歓迎してjavaアーキテクチャの交流に参加します:855835163加群リンク:https://jq.qq.com/?_wv=1027&k=5 dPqXGI群内で無料のアーキテクチャ資料を提供するほか、Javaエンジニアリング、高性能と分布式、高性能、深入浅出がある.高アーキテクチャ.パフォーマンスチューニング、Spring、MyBatis、Nettyソース分析、ビッグデータなど複数の知識ポイントの高級進級乾物の無料生放送説明 一緒に勉強してもいいですよ