Java入門 #19 - 例外処理の基本(try-catch-finally)

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

この記事の要点

例外は実行時エラーをオブジェクトとして扱う仕組み
try-catch-finally で異常系を安全にハンドリング
• Java 21 以降は try-with-resources でリソース解放が自動化

このシリーズについて

「Java入門」シリーズの第19回です。本記事では例外処理の基本構文と、checked / unchecked 例外の違いを学びます。

前提条件: #12 - クラスの基本#13 - コンストラクタとメソッド を理解していること。

例外とは

プログラムが実行中に予期しない状況に遭遇したとき、Java は 例外(Exception) を投げて異常を通知します。

状況投げられる例外
配列の範囲外にアクセスArrayIndexOutOfBoundsException
null のメソッド呼び出しNullPointerException
数値文字列でない値を parseIntNumberFormatException
0 で除算ArithmeticException
ファイルが存在しないIOException

例外が発生すると、何も対処しなければプログラムはクラッシュします。これを防ぐために try-catch を使います。

try-catch の基本構文

// Java 21 - 数値変換時の例外をキャッチする例
try {
    String input = "abc";
    int num = Integer.parseInt(input); // NumberFormatException が発生
    System.out.println(num);
} catch (NumberFormatException e) {
    System.out.println("数値に変換できません: " + e.getMessage());
}
// プログラムは続行される
ブロック役割
try { ... }例外が発生する可能性のあるコードを囲む
catch (例外型 変数) { ... }例外が投げられたときに実行される

上記の例では parseInt("abc") が失敗しますが、catch で補足されるためプログラムは停止しません

ポイント: e.getMessage() で例外の詳細メッセージを取得できます。デバッグ時は e.printStackTrace() でスタックトレースを出力すると原因特定が早くなります。

複数の catch ブロック

異なる例外型ごとに処理を分けることができます。

// Java 21 - 配列アクセスと数値変換の両方をハンドリング
String[] values = {"10", "20", "abc"};
try {
    int index = 5; // 範囲外
    int num = Integer.parseInt(values[index]);
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("配列の範囲外です");
} catch (NumberFormatException e) {
    System.out.println("数値変換に失敗しました");
}

catch は上から順に評価されます。親クラスの例外を先に書くと、子クラスの catch に到達しないため注意してください。

注意: catch (Exception e) のように親クラスを先に書くと、すべての例外をそこで捕捉してしまい、後続の catch が無視されます。具体的な例外を上に、汎用的な例外を下に配置しましょう。

finally ブロック

例外の有無に関わらず必ず実行したい処理finally に書きます。

// Java 21 - ファイルを必ず閉じる(古い書き方)
FileReader reader = null;
try {
    reader = new FileReader("data.txt");
    // 読み込み処理
} catch (IOException e) {
    System.err.println("読み込みエラー: " + e.getMessage());
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            // クローズ失敗も無視できないため二重 try が必要
        }
    }
}

finally は return 文の直前にも実行されます。ただし、ネストした try-catch が複雑になりがちです。

try-with-resources(推奨)

Java 7 以降は try-with-resources を使えば、リソースのクローズが自動化されます。

// Java 21 - try-with-resources(推奨)
try (FileReader reader = new FileReader("data.txt")) {
    // 読み込み処理
} catch (IOException e) {
    System.err.println("読み込みエラー: " + e.getMessage());
}
// try ブロックを抜けると reader.close() が自動で呼ばれる

AutoCloseable を実装したリソース(ファイル、DB接続、ネットワークソケット等)はすべて自動クローズされます。

ヒント: 複数のリソースを try (A a = ...; B b = ...) のようにセミコロン区切りで並べることもできます。閉じる順序は宣言の逆順です。

主要な例外クラス

Java 標準ライブラリが提供する代表的な例外を覚えておきましょう。

例外クラス発生する状況
NullPointerExceptionnull のメソッド呼び出し、フィールドアクセス
ArrayIndexOutOfBoundsException配列の範囲外アクセス
NumberFormatExceptionparseInt 等で文字列を数値に変換失敗
ArithmeticException0 で除算(整数演算)
IOExceptionファイル読み書き、ネットワーク通信のエラー

checked 例外 vs unchecked 例外

Java の例外は大きく2種類に分かれます。

種類意味代表例コンパイラのチェック
Checked Exception予期可能で回復可能なエラーIOException, SQLExceptiontry-catch または throws が必須
Unchecked Exceptionプログラムのバグや実行時エラーNullPointerException, ArithmeticException任意(書かなくてもコンパイル通る)

Checked ExceptionException を継承し、RuntimeException を継承していない例外です。メソッド内で発生する可能性がある場合、呼び出し側で必ず try-catch するか、メソッド宣言に throws を付ける必要があります(次回 #20 で詳説)。

Unchecked ExceptionRuntimeException を継承します。通常はバグなので、事前の if 文や論理修正で回避することが望ましく、catch は必須ではありません。

ポイント: checked 例外はコンパイル時に強制されるため、「ファイルが存在しないかもしれない」「ネットワークが切れているかもしれない」といった外部要因の異常に備えることができます。

小さな実行例:0除算の回避

// Java 21 - 0で除算しようとしたときの例外処理
import java.util.Scanner;

public class DivisionExample {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("分子を入力: ");
        int numerator = sc.nextInt();
        System.out.print("分母を入力: ");
        int denominator = sc.nextInt();

        try {
            int result = numerator / denominator;
            System.out.println("結果: " + result);
        } catch (ArithmeticException e) {
            System.err.println("エラー: 0で割ることはできません");
        } finally {
            System.out.println("処理が終了しました");
        }
    }
}

分母に 0 を入力すると ArithmeticException が発生しますが、プログラムはクラッシュせずに finally まで到達します。

プログラミングのベストプラクティス

やるべきこと理由
具体的な例外型を catch するcatch (Exception e) だけだと原因が不明瞭
ログを残すe.printStackTrace() や logger を使う
finally は本当に必要なときだけtry-with-resources で代替できるケースが多い
catch で握り潰さない空の catch ブロックは障害の温床

注意: 本番環境では printStackTrace() をコンソールに出力するのではなく、ロギングフレームワーク(SLF4J + Logback 等)を使ってファイルに記録しましょう。

次のステップ

Java入門 #20 - throws と例外の伝播 では、メソッド宣言に throws を付けて例外を呼び出し元に委譲する方法と、独自例外クラスの作り方を学びます。

参考リソース

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る