Java Silver SE17の例外処理では、例外クラスの名前を暗記するだけでは問題を解けません。
特に間違えやすいのが、次のような問題です。
tryの途中で例外が発生したら、残りの処理は実行されるのか- 複数の
catchは、どの順番で判定されるのか returnがあってもfinallyは実行されるのか- コンパイルエラーと実行時エラーのどちらになるのか
- checked例外は、どこで処理する必要があるのか
この記事では、Java Silver SE17対策として押さえておきたい例外処理問題を10問用意しました。
最初にコードだけを見て、自分で実行結果を予想してください。そのあとに「答えと解説を見る」を開き、考え方を確認しましょう。
各コードは、それぞれ独立したプログラムです。選択肢を確認してから答えを開いてください。
Java Silverの例外処理で間違えやすい5パターン
問題を解く前に、頻出パターンを整理します。
1. 例外発生後もtryブロックを読み続けてしまう
tryブロック内で例外が発生すると、その位置から対応するcatchへ処理が移ります。例外が発生した行より後ろにあるtry内の処理は実行されません。
2. catchを上から順番に確認していない
複数のcatchがある場合、上から順番に判定され、最初に一致したものだけが実行されます。
ただし、親クラスのcatchを子クラスより先に書くと、子クラス側へ到達できないためコンパイルエラーになります。
3. finallyを「例外発生時だけ動く」と考えてしまう
finallyは、例外が発生した場合だけでなく、発生しなかった場合にも原則として実行されます。tryやcatchにreturnがあっても、メソッドを抜ける前に実行されます。
4. コンパイルエラーと実行時エラーを混同する
たとえば、Integer.parseInt("abc")はコンパイルできますが、実行するとNumberFormatExceptionが発生します。
一方、checked例外を処理も宣言もせずに呼び出すコードや、catchの順番が不正なコードはコンパイルエラーです。
5. checked例外とunchecked例外を同じように扱う
checked例外は、catchで処理するかthrowsで宣言する必要があります。RuntimeExceptionとそのサブクラスはunchecked例外なので、この強制はありません。
それでは問題を解いていきましょう。
問題1:try内で例外が発生した後の実行順
public class Main {
public static void main(String[] args) {
try {
System.out.print("A");
int num = 10 / 0;
System.out.print("B");
} catch (ArithmeticException e) {
System.out.print("C");
}
System.out.print("D");
}
}選択肢:
ABCDACDAC- コンパイルエラー
答えと解説を見る
正解は 2. ACD です。
最初のSystem.out.print("A")は正常に実行されます。次の10 / 0でArithmeticExceptionが発生し、処理は対応するcatchへ移ります。
したがって、例外が発生した行より後ろにあるSystem.out.print("B")は実行されません。catchでCを出力したあと、try-catch文の次にある処理へ進み、Dが出力されます。
実行順は次のとおりです。
A → 例外発生 → C → D
問題2:例外が発生しない場合のfinally
public class Main {
public static void main(String[] args) {
try {
System.out.print("A");
int num = 10 / 2;
System.out.print(num);
} catch (ArithmeticException e) {
System.out.print("B");
} finally {
System.out.print("C");
}
}
}選択肢:
A5A5CABCAC
答えと解説を見る
正解は 2. A5C です。
10 / 2では例外が発生しないため、tryブロックが最後まで実行されます。catchは実行されません。
その後、例外の有無にかかわらずfinallyが実行され、Cが出力されます。
「例外が起きなければfinallyは動かない」という理解は誤りです。
問題3:どのcatchが実行されるか
public class Main {
public static void main(String[] args) {
try {
String value = null;
System.out.print(value.length());
} catch (NullPointerException e) {
System.out.print("A");
} catch (RuntimeException e) {
System.out.print("B");
} catch (Exception e) {
System.out.print("C");
}
}
}選択肢:
AABABC- コンパイルエラー
答えと解説を見る
正解は 1. A です。
nullが入った変数に対してlength()を呼び出すため、NullPointerExceptionが発生します。
複数のcatchは上から順番に確認されます。最初のcatch (NullPointerException e)が一致するため、Aだけが出力されます。
一度いずれかのcatchが実行されると、後続のcatchは実行されません。条件分岐のように、複数のcatchが続けて実行されるわけではありません。
問題4:catchの並び順とコンパイルエラー
public class Main {
public static void main(String[] args) {
try {
int[] values = {10, 20};
System.out.print(values[2]);
} catch (RuntimeException e) {
System.out.print("A");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.print("B");
}
}
}選択肢:
ABAB- コンパイルエラー
答えと解説を見る
正解は 4. コンパイルエラー です。
ArrayIndexOutOfBoundsExceptionはRuntimeExceptionのサブクラスです。
先に親クラスであるRuntimeExceptionを捕捉すると、その後ろにあるArrayIndexOutOfBoundsExceptionのcatchへ到達する可能性がありません。そのため、コンパイラに到達不能なcatchと判断されます。
正しい順番は、対象範囲が狭い子クラスから広い親クラスです。
} catch (ArrayIndexOutOfBoundsException e) {
System.out.print("B");
} catch (RuntimeException e) {
System.out.print("A");
}問題5:catchでreturnしてもfinallyは動くか
public class Main {
static int test() {
try {
return 10 / 0;
} catch (ArithmeticException e) {
System.out.print("A");
return 20;
} finally {
System.out.print("B");
}
}
public static void main(String[] args) {
System.out.print(test());
}
}選択肢:
A20AB20Aのあと例外で終了する- コンパイルエラー
答えと解説を見る
正解は 2. AB20 です。
tryの10 / 0でArithmeticExceptionが発生します。catchでAを出力し、戻り値として20を返そうとします。
ただし、実際にメソッドを抜ける前にfinallyが実行されるため、次にBが出力されます。その後、test()の戻り値20がmainメソッドで出力されます。
実行順は次のとおりです。
A → B → 20
問題6:finallyにもreturnがある場合
public class Main {
static int test() {
try {
return 10;
} finally {
return 20;
}
}
public static void main(String[] args) {
System.out.print(test());
}
}選択肢:
10201020- コンパイルエラー
答えと解説を見る
正解は 2. 20 です。
tryで戻り値10が決まったあと、メソッドを抜ける前にfinallyが実行されます。finallyにもreturn 20があるため、先に決まっていた戻り値10は破棄され、最終的に20が返されます。
試験問題としては重要ですが、実務でfinallyにreturnを書くのは避けるべきです。tryやcatchの戻り値だけでなく、発生した例外まで隠してしまう可能性があるからです。
問題7:unchecked例外はthrowsなしで投げられるか
public class Main {
static void check(int age) {
if (age < 0) {
throw new IllegalArgumentException("invalid");
}
}
public static void main(String[] args) {
try {
check(-1);
System.out.print("A");
} catch (IllegalArgumentException e) {
System.out.print("B");
}
}
}選択肢:
AB- 実行時に例外が捕捉されず終了する
checkにthrowsがないためコンパイルエラー
答えと解説を見る
正解は 2. B です。
IllegalArgumentExceptionはRuntimeExceptionのサブクラスであり、unchecked例外です。そのため、checkメソッドの宣言にthrows IllegalArgumentExceptionを書かなくてもコンパイルできます。
check(-1)によって例外が投げられ、対応するcatchで捕捉されるためBが出力されます。例外発生後、try内のAは実行されません。
問題8:multi-catchに継承関係がある例外を書く
public class Main {
public static void main(String[] args) {
try {
Integer.parseInt("abc");
} catch (NumberFormatException | IllegalArgumentException e) {
System.out.print("A");
}
}
}選択肢:
A- 何も表示されない
- 実行時に
NumberFormatExceptionで終了する - コンパイルエラー
答えと解説を見る
正解は 4. コンパイルエラー です。
NumberFormatExceptionはIllegalArgumentExceptionのサブクラスです。multi-catchの選択肢には、継承関係にある例外クラスを同時に指定できません。
この場合は、親クラスであるIllegalArgumentExceptionだけを指定すればNumberFormatExceptionも捕捉できます。
} catch (IllegalArgumentException e) {
System.out.print("A");
}なお、multi-catchで問題なく並べられるのは、たとえばIOException | SQLExceptionのように、互いに親子関係ではない例外です。
問題9:checked例外を処理しないコード
import java.io.IOException;
public class Main {
static void read() throws IOException {
throw new IOException();
}
public static void main(String[] args) {
read();
System.out.print("A");
}
}選択肢:
A- 実行時に
IOExceptionで終了する - 何も表示されず正常終了する
- コンパイルエラー
答えと解説を見る
正解は 4. コンパイルエラー です。
IOExceptionはchecked例外です。read()を呼び出す側は、次のどちらかで対応しなければなりません。
try-catchで例外を処理する- 呼び出し元のメソッドにも
throws IOExceptionを宣言する
このmainメソッドはどちらも行っていないため、プログラムを実行する前のコンパイル段階でエラーになります。
たとえば、次のようにすればコンパイルできます。
public static void main(String[] args) {
try {
read();
} catch (IOException e) {
System.out.print("B");
}
}問題10:catchで別の例外が発生した場合のfinally
public class Main {
public static void main(String[] args) {
try {
System.out.print("A");
throw new IllegalArgumentException();
} catch (IllegalArgumentException e) {
System.out.print("B");
throw new RuntimeException();
} finally {
System.out.print("C");
}
}
}選択肢:
ABCと表示され、正常終了するABと表示されたあと、RuntimeExceptionで終了するABCと表示されたあと、RuntimeExceptionで終了する- コンパイルエラー
答えと解説を見る
正解は 3.
ABCと表示されたあと、RuntimeExceptionで終了する
です。
まずtryでAを出力し、IllegalArgumentExceptionが投げられます。対応するcatchへ移動してBを出力しますが、そこで新しくRuntimeExceptionが投げられます。
そのままメソッドを抜ける前にfinallyが実行されるため、Cも出力されます。その後、catchから投げられたRuntimeExceptionを処理する場所がないため、異常終了します。
finallyが実行されたからといって、未処理の例外が消えるわけではありません。
catchの並び順を見抜く方法
複数のcatchが登場したら、例外クラスの継承関係を確認します。
Object
└─ Throwable
└─ Exception
└─ RuntimeException
├─ ArithmeticException
├─ NullPointerException
└─ IllegalArgumentException
└─ NumberFormatException
基本ルールは、子クラスを上、親クラスを下です。
try {
// 処理
} catch (NumberFormatException e) {
// より具体的な例外
} catch (IllegalArgumentException e) {
// より広い例外
} catch (RuntimeException e) {
// さらに広い例外
}問題を見たら、次の順番で判断しましょう。
- 発生する例外クラスを特定する
catchを上から確認する- 最初に一致する
catchを選ぶ - 親クラスが子クラスより上にないか確認する
Java言語仕様でも、例外ハンドラは左から、つまり記述された順番に検査されます。また、前のcatchで同じ例外またはその親クラスを捕捉できる場合、後ろのcatchはコンパイルエラーになります。
finallyとreturnの関係
Java
Silverでは、returnを見つけた瞬間に答えを決めないことが重要です。
次の順番で考えます。
tryまたはcatchで戻り値が決まる- メソッドを抜ける前に
finallyが実行される finallyが正常終了すれば、先に決まった値を返すfinallyにもreturnがあれば、その値で上書きされるfinallyで例外が発生すれば、元のreturnは完了しない
特に次の2つを区別してください。
try {
return 10;
} finally {
System.out.print("A");
}これはAを出力したあと、10を返します。
try {
return 10;
} finally {
return 20;
}こちらはfinallyのreturnが優先され、20を返します。
ただし、実務ではfinally内のreturnは避けましょう。制御の流れが分かりにくくなり、例外を隠す原因にもなります。
checked例外とunchecked例外の違い
| 比較項目 | checked例外 | unchecked例外 |
|---|---|---|
| 主なクラス | IOException、SQLExceptionなど |
RuntimeExceptionとそのサブクラス |
| catchまたはthrows | 必須 | 必須ではない |
| 検出される場面 | 未処理ならコンパイル時 | 主に実行時 |
| 例 | ファイル操作、DB操作など | 0除算、不正な添字、null参照など |
覚え方はシンプルです。
RuntimeExceptionの仲間ならunchecked、それ以外のExceptionの仲間は基本的にcheckedと判断します。
代表例も押さえておきましょう。
unchecked例外の代表例
ArithmeticException:整数の0除算などNullPointerException:null参照に対するメソッド呼び出しなどArrayIndexOutOfBoundsException:配列の範囲外アクセスNumberFormatException:数値に変換できない文字列の変換ClassCastException:不正な型キャスト
checked例外の代表例
IOExceptionFileNotFoundExceptionSQLExceptionClassNotFoundException
checked例外があるコードでは、catchまたはthrowsを探してください。どちらもなければ、コンパイルエラーを疑います。
Java Silverの例外処理問題を解く手順
本番で長いコードが出ても、上から漫然と読む必要はありません。
次の5点に印を付けてください。
- コンパイルエラーになる要素はないか
- 最初に例外が発生する行はどこか
- 例外発生後にスキップされる処理はどこか
- 一致する
catchはどれか finallyとreturnはあるか
特に、選択肢に「コンパイルエラー」と「実行時に例外」が両方ある場合は要注意です。
- 文法や例外処理の義務に問題がある → コンパイルエラー
- コンパイルは通るが、実行中に例外が発生する → 実行時エラー
この区別ができるだけでも、選択肢をかなり絞れます。
10問の正答一覧
| 問題 | 正解 | 学習ポイント |
|---|---|---|
| 1 | ACD |
例外発生後のtryは実行されない |
| 2 | A5C |
例外がなくてもfinallyは実行される |
| 3 | A |
最初に一致したcatchだけが動く |
| 4 | コンパイルエラー | catchは子クラスから書く |
| 5 | AB20 |
returnの前にfinallyが動く |
| 6 | 20 |
finallyのreturnが優先される |
| 7 | B |
unchecked例外にthrowsは必須でない |
| 8 | コンパイルエラー | multi-catchに親子関係の型は並べられない |
| 9 | コンパイルエラー | checked例外はcatchまたはthrowsが必要 |
| 10 | ABCのあと例外終了 |
catchから例外が出てもfinallyは動く |
まとめ:例外処理は実行順とコンパイル可否を分けて考えよう
Java Silver SE17の例外処理問題では、次のポイントが重要です。
- 例外が発生すると、
tryの残りは実行されない - 複数の
catchは上から判定され、最初に一致したものだけが動く catchは原則として子クラスから親クラスの順番で書くfinallyは例外がなくても、returnがあっても原則実行される- checked例外は
catchまたはthrowsが必要 - コンパイルエラーと実行時エラーを区別する
知識を覚えたら、実際のコード問題で「どこまで実行されるか」を追う練習が必要です。
当サイトでは、Java Silver SE17対応のコード読解問題と模擬試験を無料で公開しています。登録不要なので、例外処理以外の分野も続けて確認してみてください。

コメント