【Java】try-catchで例外処理を実装しよう!Exceptionクラスの使い方

Javaで例外処理を実装するには、try-catch処理の中でExceptionクラスを指定する必要があります。そもそも例外処理とは、

実行停止してはいけないプログラムに何らかのエラーが発生して落ちた
途中で問題が発生した場合、その後の処理を自分でコントロールしたい

のような状態を指します。この例外処理を使うことで、エラーが発生して落ちてしまう場合や問題が発生した場合の処理を自分でコントロールできるようになります。

この記事では、

  • try-catch文とは
  • try-catch文の使い方
  • finallyで必ず実行する処理を記述する方法

という基本的な内容から、

  • throwで意図的に例外を発生させる方法
  • throwsで呼び出し元で例外処理をする方法
  • 例外メッセージをカスタマイズする
  • Exceptionクラスの種類一覧
  • 独自の例外クラスの作成

などの応用的な使い方に関しても解説していきます。今回はこれらの方法を覚えるために、try-catch文のさまざまな使い方をわかりやすく解説します!

なお、Javaの記事については、こちらにまとめています。

目次

try-catch文とは

try-catch文とは、例外が発生する可能性がある処理に使うものです。try-catch文を使うことで、例外が発生しない場合の処理と、例外が発生したときの処理を分けることができます

さらに、finallyを使って例外の有無に関わらず、最後に必ず実行される処理を記述することができます。try-catch文は次のように記述します。

try {
    例外が発生する可能性のある処理
} catch (例外の型 引数) {
    例外が発生した場合の処理(例外が発生しなければ行われない処理)
} finally {
    例外の有無に関わらず、最後に必ず実行される処理
}

try-catch文の詳しい使い方はこの記事で順に解説していくので、ぜひ最後まで確認してください!

try-catch文の使い方

ここではtry-catch文の使い方を解説します。try-catch文の使い方は、tryブロックの中に例外が発生する可能性のある処理を記述し、catchブロックの中に例外が発生した後の処理を記述します。

try-catch文の使い方を次のプログラムで確認してみましょう。

public class Main {
 
    public static void main(String[] args) {
        int result;
        result = div(5, 0);
        System.out.println("戻り値 = " + result);
    }
 
    public static int div(int num1, int num2) {
        try {
            int result = num1 / num2;
            
            return result;
 
        } catch (ArithmeticException e) {
            System.out.println("例外が発生しました。");
            System.out.println(e);
 
            return 0;
        }
    }

}

実行結果:

例外が発生しました。
java.lang.ArithmeticException: / by zero
戻り値 = 0

このプログラムでは、divメソッドで割り算を行い、その結果を呼び出し元のmainメソッドに返しています。0で割り算を行っているので、ArithmeticExceptionの例外をスローして、catchブロックの中の処理が行われていることがプログラムの実行結果から確認できます。

finallyで必ず実行する処理を記述する方法

ここではfinallyの使い方を解説します。finallyブロックの中の処理は、例外の有無に関わらず、最後に必ず実行されます。そのため、finallyはファイルを開いた後に確実にcloseメソッドで閉じたいときなどに使用されます。

次のテキストファイルを読み込み表示するプログラムで、finallyの使い方を確認してみましょう。

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Main {
 
    public static void main(String[] args) {
        // 1.ファイルのパスを指定する
        File file = new File("c:SampleTest.txt");
 
        // 2.ファイルが存在しない場合に例外が発生するので確認する
        if (!file.exists()) {
            System.out.print("ファイルが存在しません");
            return;
        }
 
        // 3.FileReaderクラスとreadメソッドを使って1文字ずつ読み込み表示する
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(file);
 
            int data;
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.最後にファイルを閉じてリソースを開放する
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

実行結果:

SAMURAI
ENGINEER

このプログラムのように、finallyブロックの中でcloseメソッドを使うことで確実にファイルを閉じることができます。try-catch-finallyの使い方についてはこちらで詳しく解説しているので、ぜひ確認してください!

throwで意図的に例外を発生させる方法

ここではthrowの使い方を解説します。throwは意図的に例外をスローして、例外処理を行いたい場合に使います。次のプログラムで確認してみましょう。

public class Main {
 
    public static void main(String[] args) {
        int result;
        result = div(5, 0);
        System.out.println("戻り値 = " + result);
    }
 
    public static int div(int num1, int num2) {
        try {
            if (num2 == 0) {
                throw new ArithmeticException("0で割ったときの例外を発生させる");
            }
            int result = num1 / num2;
 
            return result;
 
        } catch (Exception e) {
            System.out.println("例外が発生しました。");
            System.out.println(e);
 
            return 0;
        }
    }

}

実行結果:

例外が発生しました。
java.lang.ArithmeticException: 0で割ったときの例外を発生させる
戻り値 = 0

このプログラムではthrowを使って、0で除算をする場合にArithmeticExceptionの例外をスローしています。

throwsで呼び出し元で例外処理をする方法

throwsの使い方を解説します。throwsは例外が発生したときにtry-catch文を使ってメソッド内で処理するのではなく、メソッドの呼び出し元で例外処理をしたい場合に使います。次のプログラムで確認してみましょう。

public class Main {
 
    public static void main(String[] args) {
        int result = 0;
        try {
            result = div(5, 0);
        } catch (Exception e) {
            System.out.println("例外が発生しました。");
            System.out.println(e);
        }
 
        System.out.println("戻り値 = " + result);
    }
 
    public static int div(int num1, int num2) throws ArithmeticException {
        int result = num1 / num2;
 
        return result;
    }

}

実行結果:

例外が発生しました。
java.lang.ArithmeticException: / by zero
戻り値 = 0

このプログラムではthrowsを使って、呼び出し元のmainメソッドで例外処理を行っています。throwとthrowsの使い方についてはこちらで詳しく解説しているので、ぜひ確認してください!

例外メッセージをカスタマイズする

例外が発生した場合に出力表示するメッセージについて、いくつかご紹介します。

これまでのサンプルコードでも、

  • System.out.println(e)
  • e.printStackTrace()

などを使って例外メッセージを出力表示しています。printStackTraceメソッドはよく使用されていますが、例外によってはメッセージが長すぎると感じる場合もあります。

例外メッセージは出来ればコンパクトなログとして残したいので、ここではgetMessageメソッドなどを使う方法などをご紹介します。

printStackTraceメソッドの使い方

以下のサンプルコードを使って例外を発生させ、printStackTraceメソッドで例外メッセージを出力表示させてみましょう。

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Main {
 
    public static void main(String[] args) {
        // FileReaderクラスとreadメソッドを使って1文字ずつ読み込み表示する
        File file = new File("c:SampleTest.txt");
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(file);
 
            int data;
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

}

実行結果:

java.io.FileNotFoundException: c:SampleTest.txt (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(FileInputStream.java:195)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
        at java.io.FileReader.<init>(FileReader.java:72)
        at Main.main(Main.java:12)

このサンプルコードでは、Fileクラスのコンストラクタで指定したファイルが見つからないため、例外FileNotFoundExceptionが発生しています。例外処理として、catchブロックでprintStackTraceメソッドを使ってメッセージを出力表示するようにしています。

getMessageメソッドの使い方

さきほどは、printStackTraceメソッドを使って例外メッセージを出力表示しました。でも、メッセージが少々長すぎるので、もう少しコンパクトになるとうれしいですよね。getMessageメソッドを使用すると、メッセージを短くすることができるのでご紹介します。

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Main {
 
    public static void main(String[] args) {
        // FileReaderクラスとreadメソッドを使って1文字ずつ読み込み表示する
        File file = new File("c:SampleTest.txt");
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(file);
 
            int data;
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }
 
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } 
    }

}

実行結果:

c:SampleTest.txt (No such file or directory)

このサンプルコードでは、getMessageメソッドを使って例外メッセージを出力表示しています。printStackTraceメソッドを使って出力表示されるメッセージの一行目「:」以降をメッセージとして表示します。

getClass、getStackTraceを使う方法

getMessageメソッドを使う方法をご紹介しましたが、これだけでは情報として少ないと感じませんか?せめて、例外の種類、例外発生場所の情報はあった方がいいかもしれません。

例外の種類の情報を記述するためには、getClassメソッドを使います。例外発生場所の情報を記述するためには、getStackTraceメソッドを使います。サンプルコードで確認しましょう。

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Main {
 
    public static void main(String[] args) {
        // FileReaderクラスとreadメソッドを使って1文字ずつ読み込み表示する
        File file = new File("c:SampleTest.txt");
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(file);
 
            int data;
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }
 
        } catch (IOException e) {
            StackTraceElement[] ste = e.getStackTrace();
            System.out.println(e.getClass().getName() + ": "+ e.getMessage());
            System.out.println("tat "+ ste[ste.length-1]); // 最後の要素の例外発生場所のみ表示
        } 
    }

}

実行結果:

java.io.FileNotFoundException: c:SampleTest.txt (No such file or directory)
        at Main.main(Main.java:12)

このサンプルコードでは、getClass().getName()メソッドとgetMessageメソッド、およびgetStackTraceメソッドを使って例外メッセージを出力表示しています。

getStackTraceメソッドはprintStackTraceメソッドを使って出力表示される「at」以降の例外発生場所の記述を配列で返します。getStackTraceメソッドで返された配列をStackTraceElement型の配列steに格納しています。

配列steの要素の中で、記述したコードの例外発生場所は最後の要素に記述されているので、最後の要素のみ出力表示しています。また、getClass().getName()メソッドを使って、該当する例外クラス名を出力表示しています。

Exceptionクラスの種類一覧

よくみかけるExceptionクラスについて表にまとめました。

例外クラス説明
java.lang.IllegalArgumentException不適切な引数引数の指定エラー
java.lang.IllegalStateException不正な状態未初期化で呼び出し
java.lang.NullPointerExceptionNullアクセス文字列の値がNull
java.lang.IndexOutOfBoundsException範囲外配列のインデックス番号がオーバー
java.lang.ArithmeticException不正な算術計算ゼロでの割り算
java.lang.NumberFormatException不正な数値型への変換変換元の文字列が数値でない
java.io.FileNotFoundExceptionファイルが開けないファイルが存在しない
java.io.IOException不正な入出力ファイルが存在しないなど

この表以外の例外クラスについては、こちらの公式サイトを参考にしてくださいね。
http://docs.oracle.com/javame/config/cdc/ref-impl/cdc1.1.2/jsr218/ja/java/lang/class-use/Exception.html

独自の例外クラスの作成

例外クラスを継承して、独自の例外クラスを作ることができます。親クラスとなる例外クラスのコンストラクタを継承して使用します。親クラスとなる例外クラスのメソッドを使用することも可能です。Exceptionクラスを継承した独自の例外クラスを使用する例をみてみましょう。

// 独自の例外クラス
class MyExc extends Exception {
    public MyExc() {
        
    }
    
    public MyExc(String msg) {
        super(msg);
    }
    
    public MyExc(Throwable cause) {
        super(cause);
    }
    
    public MyExc(String msg, Throwable cause) {
        super(msg, cause);
    }
}

public class Main {
 
    public static void main(String[] args) {
        int result;
        result = div(5, 0);
        System.out.println("戻り値 = " + result);
    }
 
    public static int div(int num1, int num2) {
        try {
            try {
                if (num2 == 0) {
                    throw new MyExc("0で割ったときの例外を発生させる");
                }
            } catch (MyExc e) {
                throw new MyExc("独自クラスの例外発生", e);
            }
            
            int result = num1 / num2;
            return result;
 
        } catch (MyExc e) {
            e.printStackTrace();
 
            return 0;
        }
    }

}

実行結果:

MyExc: 独自クラスの例外発生
        at Main.div(Main.java:35)
        at Main.main(Main.java:24)
Caused by: MyExc: 0で割ったときの例外を発生させる
        at Main.div(Main.java:32)
        ... 1 more
戻り値 = 0

このサンプルコードでは、Exceptionクラスを継承して独自の例外クラスMyExcクラスを作成しています。

Exceptionクラスでは、String型の引数を指定するコンストラクタとThrowable型の引数を指定するコンストラクタとString型、Throwable型両方の引数を指定するコンストラクタが定義されています。

MyExcクラスでもこれらのコンストラクタを「super」句を使って継承しています。Mainクラスを実行すると、String型文字列”0で割ったときの例外を発生させる”で例外を投げ、catchブロックで一旦例外を受け取ります。

さらに、一旦受け取った例外をString文字列”独自クラスの例外発生”とThrowable型変数eで例外として投げ、catchブロックで受け取っています。

まとめ

いかがでしたか? 今回はtry-catch文を使って例外処理をする方法について解説しました。例外処理が行われていないと、実行時エラーが発生したときにそこでプログラムが終了してしまうので注意してくださいね。

もし、例外処理の方法を忘れてしまったらこの記事を確認してください!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次