例外処理

想定しない入力を受け取ったり,プログラム自体のバグにより正しくない処 理をおこなったりした時は,通常の制御とは違った処理をする必要がある.こ のような処理を例外処理と言う.

練習問題のような,1回走らせたら捨ててしまうようなプログラムはともかく, 商品となるようなプログラムにおいては例外処理は必須となる.プログラミン グ言語によっては,例外処理はライブラリやOS(オペレーティングシステム)な ど言語仕様の外で扱う場合も多いが,Java言語では言語仕様にあらかじめ例外 処理を組み込んである.

例外は,さまざまなところで発生する.以下のプログラムを見てみよう.

プログラム

  // 入出力をするために必要
import java.io.*;

// キーボードから数字を入力して, 負の数を入力したら終り
class SumInput{
  public static void main(String[] args) throws IOException{
  // 入力をするためには,System.inからBufferedReaderを作らなくてはいけない
    BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
    int sum=0,num=0;
     // 条件式が常に trueなので,ループの終了は break でおこなう.
    while(true){
      String s;
        // 一行入力して文字列型変数 s に入れる
      s=d.readLine();
        // 整数値に変換する
      num=Integer.parseInt(s);
        // 負の値の時は while 文から抜ける
      if(num<0) break;
      sum+=num;
    }
    System.out.println(sum);
  }
}

実行例(下線がついているのが入力)

dell.tanaka.ecc.u-tokyo.ac.jp% java SumInput
3
2
-1
5
これで,数でないものを代入すると,次のように例外が表示されてプログラム の実行を中断する.
dell.tanaka.ecc.u-tokyo.ac.jp% java SumInput
soko
java.lang.NumberFormatException: soko
	at java.lang.Throwable.(Compiled Code)
	at java.lang.Exception.(Compiled Code)
	at java.lang.RuntimeException.(Compiled Code)
	at java.lang.IllegalArgumentException.(Compiled Code)
	at java.lang.NumberFormatException.(Compiled Code)
	at java.lang.Integer.parseInt(Compiled Code)
	at java.lang.Integer.parseInt(Compiled Code)
	at SumInput.main(Compiled Code)
このような例外が起きた時に,中断せずにプログラムで処理するために用意さ れているのが,try文である.例を見てみる.
プログラム

  // 入出力をするために必要
import java.io.*;

// キーボードから数字を入力して, 負の数を入力したら終り
class SumInput{
  public static void main(String[] args) throws IOException{
  // 入力をするためには,System.inからBufferedReaderを作らなくてはいけない
    BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
    int sum=0,num=0;
     // 条件式が常に trueなので,ループの終了は break でおこなう.
    while(true){
      String s;
        // 一行入力して文字列型変数 s に入れる
      s=d.readLine();
        // 整数値に変換する
      try{
         // この中でエラーが起きる可能性がある. 
	num=Integer.parseInt(s);
      }
        // java.lang.NumberFormatExceptionが起きた時は ここに飛ぶ
      catch(java.lang.NumberFormatException e){
	System.out.println("数字を入力してください");
          // while文を繰り返す
	continue;
      }
        // 負の値の時は while 文から抜ける
      if(num<0) break;
      sum+=num;
    }
    System.out.println(sum);
  }
}

実行例(下線がついているのが入力)

dell.tanaka.ecc.u-tokyo.ac.jp% java SumInput
3
soko
数字を入力してください
4
-1
7
try文は,
  try ブロック
  catch(エラーの引数) ブロック
  ..
  catch(エラーの引数) ブロック
  finally ブロック
という構造をしている.catchはエラーの種類に応じて複数書ける. finallyは書かなくても構わない.複数の catch を入れた例を見る.
// コマンドラインに数字列を3つ引数として与えて,足す
class SumArgs{
  public static void main(String[] args){
    int sum=0,num;
    int i;
     // 文字列の配列 argsの要素数は args.length
    for(i=0;i<3;i++){
       // 文字列からintへの変換
      try{
	num=Integer.parseInt(args[i]);
      }
      // args[i]の中身が
      catch(java.lang.NumberFormatException e){
	System.out.println("数字でない引数があったので無視します");
	continue;
      }
      // 配列の大きさが3より小さかった場合
      catch(java.lang.ArrayIndexOutOfBoundsException e){
	System.out.println("3つの数字を引数に与えてください");
	break;
      }
      // try文を抜けるときは, break, continueで抜けても実行します.
      finally{
	System.out.println("try文を抜けます");
      }
      sum=sum+num;
    }
     // 表示する
    System.out.println("sum="+sum);
  }
}

実行例

dell.tanaka.ecc.u-tokyo.ac.jp% java SumArgs soko 4
数字でない引数があったので無視します
try文を抜けます
try文を抜けます
3つの数字を引数に与えてください
try文を抜けます
sum=4

このtry文の特徴として,tryの実行部で,他のメソッドなどを読んでいて,そ のメソッドの中で例外が発生しても,catch部に飛んで来るということがある. これは,大域脱出と呼ばれる機能で,C言語では setjmp, longjmpなど機種依 存のライブラリを使う必要がある.
自分で使う例外のクラスを定義して,throw文を使うと,自由に大域脱出を定 義することができるが,この授業の範囲を超えるので,例を示すに止める.
プログラム

// 自分の使う例外として, Exceptionのサブクラス MyExceptionを定義する
class MyException extends Exception{
  // MyExceptionのインスタンス変数として,文字列型の変数sを宣言
  public String s;
  // MyException のコンストラクタ
  // 引数として文字列を持ち, インスタンス変数sに代入
  MyException(String str){
    s=str;
  }
}
class ThrowException{
  // 一部の例外(配列の添字チェック)を除いて,
  // 内部で例外を起こす可能性のあるメソッドは, throwsで例外を書く必要がある.
  static void sub() throws MyException{
    // 例外を示す MyExceptionクラスのインスタンスを作成して,
    // throwする.
    throw new MyException("execpion in sub");
  }
  public static void main(String[] args){
    try{
      System.out.println("1");
      sub();
      System.out.println("2");
    }
    // throwを実行するとここに来る.
    catch(MyException e){
      // eのインスタンス変数sを表示する.
      System.out.println(e.s);
    }
    finally{
      System.out.println("3");
    }
  }
}

実行例

dell.tanaka.ecc.u-tokyo.ac.jp% java ThrowException
1
execpion in sub
3

次へ進む