スローアブルを捕まえるのは悪い習慣ですか?
1. 概要
このチュートリアルでは、Throwableをキャッチすることの影響を見ていきます。
2. Throwableクラス
Javaのドキュメントでは、 Throwable クラスは、「Java言語のすべてのエラーと例外のスーパークラス」と定義されています。
Throwableクラスの階層を見てみましょう。
Throwable クラスには、ErrorクラスとExceptionクラスの2つの直接サブクラスがあります。
Error とそのサブクラスはチェックされていない例外ですが、Exceptionのサブクラスはチェックされているかチェックされていない例外のいずれかになります。
プログラムが失敗したときに経験する可能性のある状況の種類を見てみましょう。
3. 回復可能な状況
回復が一般的に可能であり、Exceptionクラスのチェックされたサブクラスまたはチェックされていないサブクラスのいずれかで処理できる状況があります。
たとえば、プログラムが、指定された場所にたまたま存在しないファイルを使用したい場合、チェックされたFileNotFoundExceptionがスローされます。
もう1つの例は、許可なしにシステムリソースにアクセスしようとしたプログラムで、チェックされていない AccessControl Exceptionがスローされます。
Javaのドキュメントによると、 Exceptionクラスは、「妥当なアプリケーションがキャッチしたい条件を示します」。
4. 回復不能な状況
障害が発生した場合に、プログラムが回復できない状態になる場合があります。 この一般的な例は、スタックオーバーフローが発生した場合、またはJVMのメモリが不足した場合です。
このような状況では、JVMはそれぞれStackOverflowErrorとOutOfMemoryErrorをスローします。 それらの名前が示すように、これらはErrorクラスのサブクラスです。
Javaのドキュメントによると、 Errorクラスは、「妥当なアプリケーションがをキャッチしようとしてはならない重大な問題を示しています」。
5. 回復可能および回復不可能な状況の例
呼び出し元がaddIDsToStorageメソッドを使用していくつかのストレージ機能に一意のIDを追加できるようにするAPIがあると仮定します。
class StorageAPI {
public void addIDsToStorage(int capacity, Set<String> storage) throws CapacityException {
if (capacity < 1) {
throw new CapacityException("Capacity of less than 1 is not allowed");
}
int count = 0;
while (count < capacity) {
storage.add(UUID.randomUUID().toString());
count++;
}
}
// other methods go here ...
}
addIDsToStorage を呼び出すと、いくつかの潜在的な障害点が発生する可能性があります。
- CapacityException –1未満のcapacity値を渡すときに、Exceptionのチェックされたサブクラス
- NullPointerException – のチェックされていないサブクラス例外もし nullストレージのインスタンスの代わりに値が提供されます設定
- OutOfMemoryError – JVMがwhileループを終了する前にメモリを使い果たした場合、Errorのチェックされていないサブクラス
CapacityExceptionおよびNullPointerExceptionの状況は、プログラムが回復できる障害ですが、OutOfMemoryErrorは回復不能な状況です。
6. キャッチスロー可能
APIのユーザーがaddIDsToStorageを呼び出すときに、try-catchでThrowableのみをキャッチするとします。
public void add(StorageAPI api, int capacity, Set<String> storage) {
try {
api.addIDsToStorage(capacity, storage);
} catch (Throwable throwable) {
// do something here
}
}
これは、呼び出し元のコードが回復可能な状況と回復不可能な状況に同じように反応していることを意味します。
例外を処理する際の一般的なルールは、 try-catch ブロックは、例外をキャッチする際に可能な限り具体的にする必要があるということです。 つまり、キャッチオールシナリオは回避する必要があります。
この場合のCatchingThrowableは、この一般的なルールに違反します。回復可能な状況と回復不可能な状況に別々に対応するには、呼び出し元のコードがcatch内のThrowableオブジェクトのインスタンスを検査する必要があります。 ブロック。
より良い方法は、例外の処理に特定のアプローチを使用し、回復不能な状況に対処しようとしないようにすることです。
7. 結論
この記事では、try-catchブロックでThrowableをキャッチすることの意味を調べました。
いつものように、この例の完全なソースコードは、Githubでから入手できます。