1. Top
  2. Java SE
  3. 例外処理

例外処理

例外とは

例外とは、簡単に言うとコンパイルは成功するのに、そのプログラムの実行時に発生する予期せぬエラーにより生成されるオブジェクトのことです。例外処理は実際の Javaプログラムでは必ず行うようにしましょう。優秀なプログラマやSEほど発生する例外を想定しそれに対応する堅固プログラムになっています。

具体的に実行時に発生する例外は以下のようなものがありますが、Javaではこのような例外処理のための機構を用意しています。エラーを通知するので、それに対する処理を実行することが可能になります。
・0による除算
・範囲外の配列要素へのアクセス
・ファイルのオープンができない
・データベースへ接続できない
・プログラミングでは回避できない何らかのエラー

実際に例外が発生するプログラムを見てみましょう。
public class Example{
    public static void main(String args[]){
        int a[]=new int[10];

        for(int i=0;i<11;i++){
            a[i]=100;
            System.out.println(Integer.toString(a[i]));
        }
    }
 }

【実行結果】
100
100
100
100
100
100
100
100
100
100
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at ExceptionTest.main(ExceptionTest.java, Compiled Code) 

上記のプログラムは問題なくコンパイルすることが出来ます。しかし実行してみると 0 ~ 9までの要素しか存在しない配列の 10番目の要素にアクセスした時に要素外の配列にアクセスしたことを示す例外の ArrayIndexOutOfBoundsException が発生してプログラムが停止してしまっています。


ページの先頭へ

例外処理 ( try / catch / finally )

Javaではエラーの処理や管理機能として例外処理がサポートされていて、この機能を用いて、実行中の予期せぬエラーに備えます。 Javaの例外処理は try , catch , finally, throw, throws のキーワードから構成され、例外が発生する可能性がある場合は明示的に例外を監視します。
    try {

        // 例外の発生が予測されるコード

    } catch(例外の型名 変数名) {

        // 例外が発生したときの処理

    } finally {

        // 例外をCatchしてもしなくても実行される処理

    }




try

tryステートメントは例外の発生が予測される処理ブロックを { } で囲みます。 実際に例外が監視されるのは try { } で囲まれた処理ブロックになります。


catch

tryステートメントに次にいくつかの catchステートメントを続けて記述します。catchステートメントは複数記述することが可能で、引数に例外オブジェクトを指定します。実際に例外が発生した時、JVMは catchステートメントの上から順に検索を行い、catchステートメントのパラメータと発生した例外オブジェクトが一致した時に catchブロックを実行します。

発生した例外の親クラスを引数に取る catchステートメントでも処理することが可能です。オブジェクトツリーでいうと、ArrayIndexOutOfBoundsExceptionは Throwableや Exceptionクラスでも捕捉することが可能です。

ただし先頭の catchステートメントが引数で Throwableを受け取り、次の catchステートメントで ArrayIndexOutOfBoundsExceptionを受け取るといった記述は出来ません。到達不能コードとしてコンパイルエラーになります。


finally

catchブロックが終了した時点でこのfinallyブロックが実行されます。tryブロックや、catchブロックに return ステートメントが記述されていても、この finallyブロックは必ず実行されます。 一般的に finallyブロックでは、データベースからの切断処理等を記述します。finallyブロックは省略可能です。

では先ほど例外が発生したコードを try、catch、finallyを記述してそれぞれの役割を見てみましょう。
public static void main(String args[]){

    int a[]=new int[10];

    try{

        for(int i=0;i<11;i++){
            a[i]=100;
            System.out.println(Integer.toString(a[i]));
        }

    }catch(ArrayIndexOutOfBoundsException e){
    	System.out.println("ArrayIndexOutOfBoundsExceptionが発生しました。");
    	return;
    }finally{
    	System.out.println("finallyブロックを実行します。");
    }
}

【実行結果】
100
100
100
100
100
100
100
100
100
100
ArrayIndexOutOfBoundsExceptionが発生しました。
finallyブロックを実行します。

このように例外が発生してもプログラムの実行は停止せず、catchブロックが実行されて、さらに catchブロック内に return ステートメントがあるにも関わらず finallyブロックが実行されていることが分かると思います。

もしも例外が発生したとき、プログラムを止めずに、そのまま実行させることができます。Javaでは、基本的に、例外が発生する可能性がある箇所では、必ず例外処理を記述しなければいけません!覚えておきましょう。 また SJC-Pでは finallyブロックに関する出題もありますので、きちんと理解しておきましょう。


ページの先頭へ

例外を投げる ( throw / throws )

throwsの使用方法

throwsの宣言は以下の枠内のフォーマットで構成されます。throwsで指定される例外クラスの内、チェック例外は必ず指定する必要があります。指定しない場合はコンパイルエラーとなります。非チェック例外は指定しても、指定しなくても良いです。

【例】throwsを使用し、呼び出し元メソッドで例外ハンドラがキャッチされた例です。
import java.io.*;

class Example {
    public static void main (String[] args) {
        Example ex = new Example();
        ex.methodA();
    }

    void methodA(){
        try {
            methodB(); 
        } catch(FileNotFoundException e) {
            System.err.println(e.getMessage());
        } finally {
            System.out.println("MethodA was finished");
        }
    }

    void methodB() throws FileNotFoundException {
        FileReader exFile = new FileReader("exFile.txt");
    }
}


【実行結果】
exFile.txt (指定されたファイルが見つかりません。)   ←例外処理
MethodA was finished 

【例】throwsを使用したが呼び出し元メソッドで例外ハンドラがキャッチされなかった例です。
import java.io.*;

class ExException {
    public static void main (String[] args) {
        ExException ex = new ExException();
        ex.methodA();
    }

    void methodA() {
        try {
            methodB();
        } finally {
            System.out.println("This program was finished");
        }
    }

    void methodB() throws ArithmeticException {
        System.out.println("答えは" + (100/0));
    }
}


【実行結果】
This program was finished 
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExException.methodB(ExException.java:18) 
    at ExException.methodA(ExException.java:11) 
    at ExException.main(ExException.java:6) 


オーバーライド時のthrows使用方法

メソッドのオーバーライドを行う際、throwsで指定する例外クラス型の指定方法にいくつかの注意点があります。

・スーパークラスのメソッドで指定される例外クラス型以外のチェック例外の例外クラス型をサブクラスのメソッドで指定することはできません。非チェック例外の例外クラス型は指定可能です。
・スーパークラスのメソッドで指定される例外クラス型より範囲の広い例外クラス型をサブクラスのメソッドで指定することはできません。スーパークラスのメソッドで例外クラス型FileNotFoundExceptionが指定されていた場合、そのスーパークラスである例外クラス型IOExceptionをサブクラスのメソッドに指定することはできません。

throwの使用方法

throwを使用することにより任意の場所で例外を発生させることができます。以下の枠内のフォーマットによりthrowを使用します。枠内の例外オブジェクトを参照する式には「new 例外クラス」が使用されます。

throw new 例外クラス

【例】コマンドライン引数に指定された値が10以上の場合、例外IllegalArgumentExceptionをスローする例です。
public static void main (String[] args) {
    int x = Integer.parseInt(args[0]);

    if(x >= 10) {
        throw new IllegalArgumentException("10以下の値を入力してください");
    }
}

throwで指定する例外オブジェクトがチェック例外の場合はメソッドにthrowsを指定するか同一メソッド内のcatch節内でキャッチされる必要があります。いずれも行わない場合はコンパイルエラーとなります。非チェック例外の場合は、行ってもいいですし、行わなくてもいいです。



ページの先頭へ