HOWTO · Java
JavaのRuntimeException:意味、例、チェック例外との違い
Javaにおけるjava.lang.RuntimeExceptionの意味を学び、一般的な原因を確認し、非チェックの実行時例外とチェック例外を比較します。
このページの内容
java.lang.RuntimeException は、Java における非チェック例外の基底クラスです。コンパイラはメソッドに対して、そのキャッチや throws による宣言を要求しませんが、回復が適切な場合にはプログラムでキャッチできます。実行時例外は、プログラムロジックの欠陥や、成り立つはずだった前提が崩れたことを示す場合がよくあります。
Java の java.lang.RuntimeException を理解する
実行時例外は、プログラムの実行中に発生することがあります。一般的な例には NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException があります。これらの名前は、それぞれ異なる障害を表しています。
NullPointerExceptionは、null の文字列に対してlength()を呼び出すなど、コードが null 参照を逆参照したときに発生することがあります。ArrayIndexOutOfBoundsExceptionは、コードが 0 未満、または配列の長さ以上の位置を読み書きしたときに発生することがあります。長さ 5 の配列では、有効なインデックスは 0 から 4 です。ArithmeticExceptionは、整数除算で除数が 0 のときに発生することがあります。この説明は整数除算に関するものであり、浮動小数点数の 0 による除算は Java では異なる規則に従います。
これらの例外の原因は 1 種類に限られるわけではなく、非チェックであることは処理が不可能であることを意味しません。まず、不正な状態を防ぐ方法を探してください。参照を初期化して検証し、インデックスは配列の長さから計算し、その演算で 0 が意味を持たない場合は除数をチェックします。たとえば、配列のインデックスは index >= 0 && index < numbers.length のときに有効です。
例
この完全な例では、各入力を使用前に検証し、結果の値を出力します。
public class RuntimeExceptionExample {
public static void main(String[] args) {
String text = "Java";
int[] numbers = {10, 20, 30, 40, 50};
int index = 2;
int numerator = 12;
int denominator = 3;
if (text != null) {
System.out.println("Text length: " + text.length());
}
if (index >= 0 && index < numbers.length) {
System.out.println("Selected number: " + numbers[index]);
}
if (denominator != 0) {
System.out.println("Quotient: " + numerator / denominator);
}
}
}
Text length: 4
Selected number: 30
Quotient: 4
文字列は存在し、選択したインデックスは配列の範囲内にあり、除数は 0 ではありません。ここで説明した null の逆参照、無効な配列インデックス、除数 0 のケースは実行されませんでした。これらの障害のいずれかが発生すると、対応する実行時例外がスローされます。例外がキャッチされない場合、その実行パスでは失敗した操作の後にある文は実行されません。各障害を実演するには、入力を 1 つずつ変更し、そのケースを個別に処理してください。キャッチされない障害を複数連続して並べても、それぞれに到達するとは期待できません。
プログラムに意味のある回復アクションがある場合、キャッチは有用ですが、プログラミングの欠陥を隠すだけの広範なキャッチは診断を困難にします。入力はプログラムに入る場所の近くで検証し、予期しない状態の原因を修正することを優先してください。テストとデバッグはそのような欠陥の発見に役立ち、コード解析ツールも一部の危険なパターンを指摘できます。
java.lang.RuntimeException と java.lang.Exception の違い
java.lang.RuntimeException は java.lang.Exception を拡張しているため、すべての実行時例外は例外でもあります。ただし、java.lang.Exception には、RuntimeException を拡張しないチェック例外のサブクラスもあります。実務上の違いは、原因が外部にあるかどうかや、開発者がキャッチできるかどうかではなく、コンパイラの処理要件にあります。
チェック例外は、キャッチするか、メソッドの throws 句で宣言しなければなりません。たとえば、チェック例外を宣言する API を呼び出すコードは、コンパイルするためにその例外を考慮しなければなりません。NullPointerException のような非チェック例外については、Java は対応するキャッチまたは宣言の要件を課しません。チェック例外も非チェック例外も try と catch でキャッチできます。実行時例外のキャッチが適切なのは、コードが有用で明確な回復アクションを実行できる場合です。
Error は Throwable の下にある別の分岐であり、Exception のサブクラスではありません。この区別は、コンパイラのチェック例外に関する規則が、RuntimeException のサブクラスと Error のサブクラス以外の例外型に適用される理由を説明するのに役立ちます。
キャッチされない例外は、それが発生したスレッドを終了させます。メインスレッドから漏れた場合、アプリケーションが終了することがあります。別のスレッドでキャッチされない例外が発生しても、それ自体がすべてのスレッドの停止を意味するわけではありません。処理は障害に合わせるべきです。プログラムに確実な回復方法がある場合は回復し、プログラムを意図しない状態のままにする欠陥は修正してください。
まとめ
java.lang.RuntimeException は非チェックであるため、キャッチは可能であるにもかかわらず、Java はそのキャッチや宣言を要求しません。null の逆参照、無効な配列インデックス、整数の 0 除算が一般的な例です。可能な場合は値を検証し、根本的な欠陥を修正してください。catch ブロックは、明確な回復アクションを支える場合に使用します。キャッチされない例外はそのスレッドを終了させますが、アプリケーション全体への影響はどのスレッドが失敗したかによって異なることを覚えておいてください。