
Java道|例外処理が必須ではない例外
全部の例外に身構えなくても大丈夫。
Javaの例外は、種類によって「必ず対応が必要なもの」と「明示的な対応が必須ではないもの」に分かれています。
Javaの例外処理を学んでいると、最初は次のように感じやすいです。
「例外が起きるなら、全部 try-catch で囲まないといけないのかな」
「例外があるメソッドには、毎回 throws を書かないといけないのかな」
たしかに、これまで学んできた TrainingException のような独自例外では、メソッドを使う側が try-catch で受け取るか、throws でさらに呼び出し元へまかせる必要がありました。
しかし、Javaの例外はすべて同じ扱いではありません。
例外には、明示的な例外処理が求められるものと、必ずしも求められないものがあります。
今回の記事では、鬼殺隊の重力修行装置を例にしながら、例外処理が必須ではない例外 について整理していきます。使用するプログラムは Sample5.java です。
鬼滅の刃風にたとえると、すべての異常事態に同じ手順で対応するわけではありません。
| 異常の種類 | 鬼滅の刃風のイメージ | Javaでの扱い |
|---|---|---|
| 修行装置の設定ミス | 重力設定がマイナスになっている | 独自例外で利用者に対応を求める |
| 名簿の記入ミス | 5人分の欄しかないのに10番目へ記録する | RuntimeException 系のミス |
| 本部全体の重大異常 | 訓練場そのものが崩れ始める | Error 系の重大問題 |
このように、同じ「異常」でも性質が違います。
Javaでは、この違いを例外クラスの分類によって表しています。
すべての例外で同じ対応が必要なわけではない
Javaでは、例外が起きる可能性がある場合でも、すべてに対して必ず try-catch や throws を書く必要があるわけではありません。
大きく分けると、次のように整理できます。
| 分類 | 基本の考え方 |
|---|---|
| Error のサブクラス | 致命的な問題なので、通常は明示的な例外処理を求めない |
| RuntimeException のサブクラス | プログラムの使い方や書き方で防ぐべきことが多く、明示的な例外処理を必須としない |
| Exception のうち RuntimeException 以外 | 明示的な try-catch または throws が必要になることが多い |
ここで大切なのは、Exception の仲間だから全部同じ ではないという点です。
Exception の中にも、RuntimeException の仲間と、それ以外の例外があります。
| 例外の種類 | 明示的な処理 |
|---|---|
| RuntimeException 系 | 必須ではない |
| RuntimeException 以外の Exception 系 | 必要になることが多い |
たとえば、今回の TrainingException は Exception を継承していますが、RuntimeException は継承していません。
そのため、TrainingException を送出するメソッドを呼び出す側は、try-catch で受け取るか、throws で呼び出し元へ渡す必要があります。
Error の仲間は通常の例外処理の中心ではない
Error は、Javaの例外階層の中では Throwable の下にあるグループです。
しかし、通常のアプリケーションで細かく try-catch して立て直す対象としては扱われにくいです。
| 分類 | 内容 |
|---|---|
| Error | 実行環境やシステム全体に関わる深刻な問題を表すことが多い |
| 例 | メモリ不足など、通常の処理で簡単に回復しにくい問題 |
| 基本的な考え方 | 通常は細かく catch して処理する対象にしない |
鬼滅の刃風にたとえると、Error は修行者の記録ミスではなく、訓練場そのものが崩れ始めるような事態です。
たとえば、修行名簿の番号を間違えたなら、記録係が修正できます。
しかし、訓練場全体の結界が壊れ、建物が崩れそうになっている場合は、通常の修行処理を続けるどころではありません。
| 鬼滅の刃風の状況 | Javaのイメージ |
|---|---|
| 修行名簿の記入ミス | プログラム側で見直せる可能性がある |
| 重力設定の不正値 | 例外として利用者に判断を求められる |
| 訓練場全体の崩壊 | Error に近い重大な問題 |
そのため、Error の仲間は、学習の基本では「通常の例外処理の主役ではない」と考えると分かりやすいです。
RuntimeException の仲間は明示的な処理を必須としない
RuntimeException は、実行中に起こる例外のうち、プログラムの書き方や使い方が原因になることが多いグループです。
代表的なものには、次のような例外があります。
| 例外 | 起きる状況 |
|---|---|
| ArrayIndexOutOfBoundsException | 配列の範囲外にアクセスした |
| NullPointerException | null の参照先を使おうとした |
| NumberFormatException | 数字に変換できない文字列を変換しようとした |
これらは、もちろん起きてよい問題ではありません。
しかし、Javaはこれらに対して、毎回必ず try-catch または throws を書くことまでは求めません。
なぜなら、RuntimeException 系の多くは、例外が起きたあとに受け止めるよりも、そもそも起きないようにコードを直すことが大切だからです。
鬼滅の刃風にたとえると、5人分の修行名簿しかないのに、10番目の欄へ記録しようとするようなものです。
この場合、警告を受け取る仕組みを毎回書くよりも、まずは次のように考えるほうが自然です。
| 問題 | 本質的な対策 |
|---|---|
| 存在しない欄に記録しようとした | 添字の範囲を確認する |
| null の隊士情報を使おうとした | オブジェクトが作られているか確認する |
| 数字でない札を数値として読んだ | 入力値を確認する |
RuntimeException は、必要なら catch できます。
ただし、言語として明示的な例外処理を必須にはしていません。
図:例外処理が必須かどうかの全体像
↓クリックすると拡大表示されます。

この図が示していること
この図では、Javaの例外階層を「例外処理が必須かどうか」という観点で整理しています。
Throwable の下には Error と Exception があります。
Error は通常の例外処理の中心にはしません。
Exception の中でも、RuntimeException の仲間は明示的な try-catch や throws を必須とはしません。
一方、RuntimeException 以外の Exception は、明示的な処理が必要になることが多いです。
| 図の要素 | 分かること |
|---|---|
| Error | 致命的な問題として扱われやすい |
| RuntimeException | 明示的な例外処理を必須としない |
| RuntimeException 以外の Exception | try-catch または throws が必要になることが多い |
この図から分かることは、例外はすべて同じ扱いではなく、種類によって対応の必要性が変わるということです。
checked exception と unchecked exception
ここで、よく使われる用語も整理しておきます。
Javaの例外は、明示的な処理が必要かどうかという観点で、次のように分けられます。
| 分類 | 内容 |
|---|---|
| checked exception | try-catch で処理するか、throws で渡す必要がある例外 |
| unchecked exception | 明示的な try-catch や throws を必須としない例外 |
unchecked exception にあたる代表が、RuntimeException とそのサブクラスです。
Error も、通常は明示的な例外処理を要求されない側として考えます。
| 種類 | 分類のイメージ |
|---|---|
| RuntimeException 系 | unchecked exception |
| Error 系 | unchecked 側として扱われる |
| RuntimeException 以外の Exception 系 | checked exception |
今回の Sample5.java で使う TrainingException は、Exception を継承しています。
class TrainingException extends Exception
{
}ただし、RuntimeException は継承していません。
そのため、TrainingException は checked exception として扱われます。
つまり、setTraining メソッドが TrainingException を送出する可能性を持つなら、呼び出し側はその対応を考える必要があります。
Sample5.javaで使うTrainingExceptionの位置づけ
ここでは、前の記事で使用した Sample5.java を使用します。このプログラムでは、TrainingException という独自例外を作っています。
これは、鬼殺隊の重力修行装置で不正な重力設定が指定されたときに送出される例外です。
ファイル名:Sample5.java
class TrainingException extends Exception
{
}
// 修行装置クラス
class TrainingMachine
{
private int level;
private double gravity;
public TrainingMachine()
{
level = 0;
gravity = 0.0;
System.out.println("鬼殺隊の重力修行装置を起動しました。");
}
public void setTraining(int l, double g) throws TrainingException
{
// 重力が負の値なら異常として例外を送出する
if(g < 0)
{
TrainingException e = new TrainingException();
throw e;
}
else
{
level = l;
gravity = g;
System.out.println("修行レベルを" + level + "に、重力を" + gravity + "に設定しました。");
}
}
public void show()
{
System.out.println("現在の修行レベルは" + level + "です。");
System.out.println("現在の重力設定は" + gravity + "です。");
}
}
class Sample5
{
public static void main(String[] args)
{
TrainingMachine machine1 = new TrainingMachine();
try
{
machine1.setTraining(3, -50.0);
}
catch(TrainingException e)
{
System.out.println(e + " が送出されました。");
}
machine1.show();
}
}このプログラムでは、TrainingException が Exception を継承しています。
class TrainingException extends Exception
{
}この TrainingException は、RuntimeException の仲間ではありません。
そのため、setTraining メソッドでは、次のように throws TrainingException を書いています。
public void setTraining(int l, double g) throws TrainingExceptionこれは、呼び出し側に対して、
「このメソッドでは TrainingException が送出される可能性があります」
と知らせるための宣言です。
TrainingExceptionはなぜ明示的な処理が必要なのか
TrainingException は、Exception を継承した独自例外です。
RuntimeException ではないため、Javaは呼び出し側に対して、明示的な対応を求めます。
つまり、setTraining メソッドを呼び出す側は、次のどちらかを選ぶ必要があります。
| 対応 | 内容 |
|---|---|
| try-catch で受け取る | その場で TrainingException に対応する |
| throws でさらに渡す | 自分では処理せず、呼び出し元へまかせる |
今回の Sample5.java では、main メソッドの中で try-catch を使って受け取っています。
try
{
machine1.setTraining(3, -50.0);
}
catch(TrainingException e)
{
System.out.println(e + " が送出されました。");
}これは、TrainingException が送出された場合に、main メソッド内で受け止める形です。
鬼滅の刃風にたとえると、重力修行装置が危険な設定値を検知して警告札を投げたとき、近くに待機している支援隊士がその札を受け取るようなものです。
| Javaの処理 | 鬼滅の刃風のイメージ |
|---|---|
| setTraining が TrainingException を送出する | 修行装置が警告札を投げる |
| throws TrainingException | 修行場の入口に注意書きを出す |
| catch(TrainingException e) | 支援隊士が警告札を受け取る |
| machine1.show() | 修行装置の現在状態を確認する |
実行結果
このプログラムを実行すると、次のようになります。
鬼殺隊の重力修行装置を起動しました。
TrainingException が送出されました。
現在の修行レベルは0です。
現在の重力設定は0.0です。setTraining(3, -50.0) では、重力 g に -50.0 を渡しています。
machine1.setTraining(3, -50.0);setTraining メソッドでは、g < 0 の場合に TrainingException を送出します。
if(g < 0)
{
TrainingException e = new TrainingException();
throw e;
}そのため、level と gravity に新しい値は設定されません。
| 項目 | 値 |
|---|---|
| 渡した修行レベル | 3 |
| 渡した重力設定 | -50.0 |
| 実際の level | 0 |
| 実際の gravity | 0.0 |
| 理由 | throw により通常の設定処理が中断されたため |
このように、TrainingException は明示的に扱う必要がある例外として設計されています。
RuntimeExceptionならどう違うのか
ここで、RuntimeException の仲間と比べてみましょう。
たとえば、ArrayIndexOutOfBoundsException は RuntimeException のサブクラスです。
配列の範囲外アクセスで起きる例外です。
int[] power = new int[5];
power[10] = 9000;このようなコードでは、実行時に ArrayIndexOutOfBoundsException が発生します。
しかし、Javaはこのコードに対して、
「必ず try-catch で囲んでください」
「必ず throws を書いてください」
とは求めません。
| 例外 | 系統 | 明示的な処理 |
|---|---|---|
| TrainingException | Exception 系で RuntimeException ではない | 必要 |
| ArrayIndexOutOfBoundsException | RuntimeException 系 | 必須ではない |
RuntimeException 系の例外は、主にプログラムの書き方や使い方によって防ぐべきものとして扱われます。
鬼滅の刃風にたとえると、配列の範囲外アクセスは、修行名簿の存在しない欄に記録しようとするようなものです。
このようなミスは、毎回支援隊士を待機させるよりも、まず名簿の範囲を正しく確認するほうが本質的です。
| RuntimeException 系の例 | 本質的な対策 |
|---|---|
| 配列の範囲外アクセス | 添字が範囲内か確認する |
| null の利用 | オブジェクトが存在するか確認する |
| 数値変換失敗 | 変換前に入力内容を確認する |
もちろん、必要に応じて RuntimeException 系の例外を catch することはできます。
ただし、Javaの言語ルールとして明示的な処理は必須ではありません。
図:TrainingExceptionとRuntimeExceptionの違い
↓クリックすると拡大表示されます。

この図が示していること
この図では、TrainingException と RuntimeException 系の例外の違いを比較しています。
TrainingException は Exception を継承していますが、RuntimeException ではありません。
そのため、明示的な try-catch または throws が必要になります。
一方、ArrayIndexOutOfBoundsException のような RuntimeException 系の例外は、明示的な処理を必須とはしません。
| 比較 | TrainingException | RuntimeException 系 |
|---|---|---|
| 分類 | checked exception | unchecked exception |
| 明示的な処理 | 必要 | 必須ではない |
| 考え方 | 利用者に対応を求める | まずコードの見直しで防ぐ |
| 鬼滅の刃風 | 修行装置が正式に出す警告札 | 名簿の使い方ミス |
この図から分かることは、例外の種類によって「利用者に対応を強制するかどうか」が変わるということです。
throwsが付いているメソッドは利用者への合図
throws は、メソッドを使う側にとって大切な合図です。
Sample5.java では、setTraining メソッドに throws TrainingException が付いています。
public void setTraining(int l, double g) throws TrainingExceptionこれは、メソッドを使う側に対して、次のように伝えています。
「このメソッドでは、TrainingException が送出される可能性があります。対応方法を考えてください」
そのため、main メソッドでは try-catch を使っています。
try
{
machine1.setTraining(3, -50.0);
}
catch(TrainingException e)
{
System.out.println(e + " が送出されました。");
}このように、throws は設計者から利用者への注意書きになります。
| 立場 | 役割 |
|---|---|
| クラス設計者 | 危険な状態を TrainingException として定義する |
| setTraining メソッド | throws で例外の可能性を宣言する |
| クラス利用者 | try-catch または throws で対応を選ぶ |
鬼滅の刃風にたとえると、修行装置の設計者が、入口に次のような札を出している状態です。
「この装置は、危険な重力値が入ると警告を出します。使用者は対応を準備してください」
この注意書きがあることで、使う側は警告が出る可能性を前提に処理を組み立てられます。
クラス設計者と利用者の役割分担
例外処理は、単にエラーを止めるためだけの仕組みではありません。
クラスを作る人と、クラスを使う人の役割を分けるための仕組みでもあります。
TrainingMachine クラスを作る人は、重力がマイナスなら危険だと判断できます。
if(g < 0)
{
TrainingException e = new TrainingException();
throw e;
}しかし、その例外が起きたときにどう対応するかは、利用者によって変わるかもしれません。
| 利用者がしたい対応 | 例 |
|---|---|
| メッセージを表示したい | 重力設定が不正です と表示する |
| 再入力させたい | 正しい重力値をもう一度入力させる |
| ログに残したい | 異常値を記録して処理を続ける |
| 上位の管理処理へ任せたい | 自分のメソッドにも throws を付ける |
もし TrainingMachine クラスの中で、すべての対応を固定してしまうと、利用者は柔軟に動けません。
そのため、TrainingMachine は「危険な値を検知して例外を送出する」役割を持ち、利用者は「その例外をどう扱うか」を決めます。
鬼滅の刃風にたとえると、修行装置は危険値を検知して警告札を出します。
その警告札を見て、現場の支援隊士が修行を止めるのか、再設定させるのか、本部へ報告するのかを決めるわけです。
例外処理が必須ではない例外がある理由
ここまで見ると、例外処理が必須ではない例外がある理由も見えてきます。
Javaは、例外の性質によって役割を分けています。
| 例外の種類 | Javaの考え方 |
|---|---|
| checked exception | 利用者に明示的な対応を求める |
| RuntimeException 系 | コードの使い方を見直して防ぐことが多い |
| Error 系 | 通常のアプリケーション処理で立て直しにくい |
たとえば、TrainingException は、クラス設計者が「この異常は利用者に対応を考えてほしい」と示すために使っています。
一方、RuntimeException 系の例外は、主にプログラムの誤った使い方によって起きることが多いため、毎回明示的な処理を書くよりも、まず正しいコードに直すことが重視されます。
Error 系は、さらに深刻な問題を表すため、通常の try-catch の中心にはしません。
鬼滅の刃風に整理すると、次のようになります。
| Javaの分類 | 鬼滅の刃風の例え | 対応の考え方 |
|---|---|---|
| checked exception | 修行装置が正式に出す警告札 | 利用者が受け取り方を考える |
| RuntimeException | 修行名簿の使い方ミス | コードや使い方を見直す |
| Error | 訓練場全体の崩壊 | 通常の現場処理では扱いにくい |
このように、Javaはすべての例外を同じルールで扱うのではなく、性質ごとに分けています。
図:設計者と利用者の役割分担
↓クリックすると拡大表示されます。

この図が示していること
この図では、例外処理におけるクラス設計者と利用者の役割分担を表しています。
TrainingMachine を作る側は、危険な重力設定を検知し、TrainingException を送出するように設計します。
setTraining メソッドには throws TrainingException が付いているため、利用者は例外が起きる可能性を知ることができます。
利用者は、その例外を try-catch で受け取るか、さらに throws で上位へ渡すかを選びます。
| 役割 | 内容 |
|---|---|
| クラス設計者 | どんな状態を例外にするか決める |
| throws | 利用者に例外の可能性を知らせる |
| クラス利用者 | try-catch または throws で対応を選ぶ |
| RuntimeException | 明示的な対応を必須としない |
| Error | 通常の例外処理の中心にしない |
この図から分かることは、例外処理は単なるエラー対応ではなく、クラス設計者と利用者の役割を分けるための仕組みでもあるということです。
明示的な処理が必要な例外と不要な例外を見分ける感覚
学習段階では、次のように考えると整理しやすいです。
| 見分け方 | 考え方 |
|---|---|
| throws が付いている | 呼び出し側に明示的な対応を求めている可能性が高い |
| RuntimeException 系 | try-catch や throws は必須ではない |
| Error 系 | 通常の例外処理の主役ではない |
| Exception だが RuntimeException ではない | checked exception として扱われることが多い |
Sample5.java の setTraining メソッドは、throws TrainingException を持っています。
public void setTraining(int l, double g) throws TrainingExceptionそのため、呼び出し側は次のように備えています。
try
{
machine1.setTraining(3, -50.0);
}
catch(TrainingException e)
{
System.out.println(e + " が送出されました。");
}この流れは、checked exception の考え方を理解するうえでとても分かりやすい例です。
一方で、RuntimeException 系の例外では、Javaは必ずしもこのような明示的処理を求めません。
例外処理が必須ではないから放置してよいわけではない
ここで注意したいのは、RuntimeException 系の例外は「処理が必須ではない」だけであって、「気にしなくてよい」という意味ではないことです。
たとえば、ArrayIndexOutOfBoundsException が起きるコードを放置してよいわけではありません。
int[] power = new int[5];
power[10] = 9000;このコードは、コンパイル上は try-catch や throws がなくても問題にされないことがあります。
しかし、実行すれば配列の範囲外アクセスで例外が発生します。
つまり、明示的な例外処理が必須ではないからといって、安全なコードになるわけではありません。
| 誤解 | 正しい理解 |
|---|---|
| RuntimeException は処理不要だから無視してよい | 明示的な処理が必須ではないだけで、原因の修正は必要 |
| Error は catch しなくてよいから気にしなくてよい | 通常の例外処理で扱いにくい重大問題として理解する |
| checked exception だけ気にすればよい | unchecked exception もバグの原因として重要 |
鬼滅の刃風にたとえると、名簿の範囲外に記録しようとするミスは、正式な警告札の受け取り手順が必須ではないとしても、直さなくてよいわけではありません。
むしろ、最初から正しい欄に記録するように修正することが大切です。
この記事で押さえておきたいこと
例外処理が必須ではない例外を理解するには、例外の分類を見ることが大切です。
| ポイント | 内容 |
|---|---|
| すべての例外で同じ対応は不要 | 例外の種類によって扱いが違う |
| Error の仲間 | 致命的な問題として、通常の例外処理の中心にはしない |
| RuntimeException の仲間 | 明示的な try-catch や throws を必須としない |
| Exception のうち RuntimeException 以外 | try-catch または throws が必要になることが多い |
| TrainingException | Exception を継承し、RuntimeException ではないため明示的な対応が必要 |
| throws の意味 | 利用者に例外処理の判断を求める合図 |
| unchecked exception | 明示的な処理は必須ではないが、原因の見直しは重要 |
Javaの例外処理では、例外があるから全部 catch する、という考え方ではなく、例外の種類に応じて対応を考えることが大切です。
TrainingException のように、クラス設計者が利用者に明示的な対応を求める例外もあります。
一方で、RuntimeException のように、明示的な処理を必須とはせず、コードの正しさで防ぐべきものもあります。
さらに、Error のように、通常の例外処理の中心にはしない重大な問題もあります。
鬼滅の刃風に言えば、修行装置が正式に出す警告札、修行名簿の使い方ミス、訓練場全体の崩壊は、それぞれ扱い方が違います。
この違いが分かると、try-catch、throws、RuntimeException、Error の関係がかなり整理しやすくなります。
