なぜJavaがスローされなくてもException
をキャッチできますが、そのサブクラスをキャッチできません( "unchecked" RuntimeException
sおよびこれはサブクラスです。コード例:
class Test {
public static void main(String[] args) {
try {
// do nothing
} catch (Exception e) {
// OK
}
try {
// do nothing
} catch (IOException e) {
// COMPILER ERROR: Unreachable catch block for IOException.
//This exception is never thrown from the try statement body
}
}
}
何か案は?
RuntimeException
はanyコードによってスローされる可能性があります。言い換えると、コンパイラーは、どのようなコードがそれをスローできるかを簡単に予測することができません。 RuntimeException
はcatch(Exception e)
ブロックによってキャッチできます。
ただし、IOException
は確認済みの例外です。例外をスローするように宣言されているメソッド呼び出しのみが実行できます。コンパイラーは、それをスローするように宣言されているメソッド呼び出しがない限り、発生する可能性がないことを(合理的に)確信できます。
Javaコンパイラは、「tryブロック内にコードがまったくない」状況を単に考慮しません-すべての場合と同様に、常にチェックされていない例外をキャッチできますreasonable =シナリオにはコードがありますcouldチェックされていない例外をスローする可能性があります.
JLSの セクション14.21 から:
キャッチブロックCは、次の両方に該当する場合に到達可能です。
- Tryブロック内の一部の式またはthrowステートメントは到達可能で、catch句Cのパラメーターに割り当て可能なタイプの例外をスローできます(式は、それを含む最も内側のステートメントが到達可能である場合に到達可能と見なされます)。
- Cのパラメーターの型がAのパラメーターの型と同じか、そのサブクラスであるような、tryステートメントには以前のcatchブロックAはありません。
おそらくコンパイラは、最初の場合、tryブロック内にno式があることを認識すべきです...私には、これはまだ到達できないcatch句のようです。
編集:コメントに記載されているように、 セクション14.2 には以下が含まれます。
catch
句がチェックされた例外タイプE1をキャッチしたが、チェックされた例外タイプE2が存在せず、以下のすべてが成立する場合、これはコンパイル時エラーです:
- E2 <:E1
try
句に対応するcatch
ブロックはE2をスローできます- 直前のtryステートメントの先行する
catch
ブロックは、E2またはE2のスーパータイプをキャッチしません。E1がクラス例外でない限り。
だから、それはあなたがそうしているように見えます実際にファウルの実行ですが、仕様は、14.21の到達不能なcatchブロックの点でそうである可能性があるほど明確ではありません。
コードにIOExceptionをスローする何かがあるとコンパイラが予測した場合にのみ、IO例外をキャッチできます。したがって、IO例外がtryステートメントの本文からスローされることはないという警告が表示されます(tryの本文には何もないため)。
チェックされた例外の場合、それらをスローしているメソッドは、「throws」キーワードによってこの事実を明示的に示す必要があるため、ブロックに「throws IOException」がない場合、コンパイラーはそれを不可能 IOExceptionがスローされるため、キャッチした後で何をしても、到達できなくなります。
スローされないチェック例外はスローできないため、キャッチできません。未チェックのランタイム例外IS Exception
およびCOULDがスローされる可能性があるため、Exception
をキャッチできます。
IOException
は、IO関連コードによってのみスローされるチェック済み例外です。tryブロックは何も実行しないため、何もIO関連が発生することはありません、IOExceptionsがスローされることはないため、catchブロックが実行されることはなく、コンパイラーはそれを回避できません。前述のように、Exceptionはいつでも発生する可能性がある未チェックのランタイム例外を参照する場合があります。これが、チェックされていない例外とチェックされた例外の主な違いです。そのため、コンパイラは、実行可能なすべての例外をキャッチするようにコードを強制しません。
単にJavaは、すべてのコード行が一般的なException
またはThrowable
、つまりOutOfMemoryException
であるError
をスローできると想定しています_むしろException
。同じことがNPEにも当てはまります。
IOException
は、マネージコードによってのみスローされる特定の例外であるため、catchブロックにI/O呼び出しがない場合、コンパイラーはそれをキャッチする機会がありません。
C#の世界と比較すると、C#ではそのようなコードはコンパイルされますが、何もしなければキャッチブロックに到達しないため、概念上の間違いになります。 ReSharperなどのツールは、そのことを警告することができます。