独自例外クラスの作成

Revised: Mar./21st/2002: Since: Jan./27th/2002

適当な例外クラスを継承して、独自定義の例外クラスを作ることも出来ます。例外クラスは java.lang.Throwable のサブクラスであり、 throw できますし、メソッドの throws リストに加えることも出来ます。また、スーパークラスに選んだ例外クラスによっては、そのクラスで定義しされた特殊なメソッドが使えることもあります。

このとき、 RuntimeException を継承すれば、 catch したり、メソッドの throws リストに指定する必要はなくなります。しかし、明示的な例外のスローは、戻り値や引数と同様なメソッドのインタフェースの一部だからこそ有意義なのだと言えます。通常は Exception クラスから継承して、上位の制御でキャッチします。

サンプル

具体的な例を作ってから、それに合わせて例外クラスを定義してみます。

次の例は、ユーザ名の配列を保持するクラスです。インスタンス化のときにコンストラクタにユーザ名の配列を与えます。特定のユーザを表す要素のインデックスを、当該ユーザの ID として、 ID からユーザ名を、ユーザ名から ID を得ることが出来ます。

class UserList {
	private String[] users;
	// ユーザの配列を代入
	void setUsers(String[] args) {
		// 配列の参照の値の代入
		users=args;
	}
	// UID からユーザ名を取得
	String getUser(int uid) {
		return users[uid];
	}
	// ユーザ名から UID を取得
	int getUser(String user) {
		for (int i=0; i<users.length; i++) {
			if (user.equals(users[i])) {
				return i;
			}
		}
		// 整数値を返す必要があるので、
		// ここではデフォルトは 0 とした。
		return 0;
	}
}

このクラスは文字列型の配列を保持し、メソッドにはそのゲッター (getXyz()) とセッター (setXyz()) が定義されています。このクラスを使うコントロールクラスを次のように定義してみます。

UserTest.java:

class UserTest {
	public static void main(String[] args) {
		// インスタンス化
		UserList obj = new UserList();
		// ユーザ配列のセット
		obj.setUsers(args);
		System.out.print("sugai -> ");
		System.out.println(obj.getUser("sugai"));
		System.out.print("0 -> ");
		System.out.println(obj.getUser(0));
	}
}

上で挙げた UserList クラスはこのクラスと同じファイルに記述しても構いませんし、分けても構いません。但し、同じディレクトリに存在していることが必要です。ファイルに保存できたら実行してみます。

実行例:

C:\Java\Excep>javac UserTest.java
C:\Java\Excep>java UserTest root team01 team02 sugai system admin
sugai -> 3
0 -> root

サンプル

例外クラスの定義

ここで定義した UserList クラスにはプリミティブな問題が散見されます。

  1. ユーザが見付からなければデフォルト値 "0" を返しているのは乱暴
  2. "uid" の適正値がアサインされない場合の処理がない
  3. ユーザリストが存在しない場合が考慮されていない

このような問題を解決する為に、ここでは独自の例外クラスを定義してみます。

UserNotAuthorizedException
ユーザが見付からない場合に発生
UidOutOfBoundException
指定された UID が適切な範囲内ではない場合に発生
NullUsersException
ユーザがセットされる前にユーザが要求された場合に発生

このように、独自の定義で例外を作る場合は、末尾を Exception にするのが命名慣例 (naming convention) です。

これらの例外クラスをこれから作りますが、スーパークラス UsersException を作って、それから派生させることにします。この例外クラスは Exception クラスの派生として作ります。

// UserList クラスが発生する例外のスーパークラス
class UsersException extends Exception {
	public UsersException(String str) {
		super(str);
	}
}
class UserNotAuthorizedException extends UsersException {
	// UID
	private int id;
	// ユーザ名
	private String name;
	// コンストラクタ
	public UserNotAuthorizedException() {
		super("このユーザは認証されません。");
	}
	public void setUid(int i) {
		id = i;
	}
	public void setName(String user) {
		name = user;
	}
	public String getName() {
		return name;
	}
	public int getId() {
		return id;
	}
}
class UidOutOfBoundException extends UsersException {
	// UID の上限
	private int hid;
	// コンストラクタ(引数は UID の上限)
	public UidOutOfBoundException(int i) {
		super("UID の範囲は" + 0 + "から" + i + "です。");
		hid = i;
	}
	public int getHid() {
		return hid;
	}
}
class NullUsersException extends UsersException {
	// コンストラクタ
	NullUsersException() {
		super("ユーザが定義されていません。");
	}
}

これらの例外クラスをコンパイルしてバイトコード(*.class ファイル)を用意しておきます。

C:\Java\Excep>javac UsersException.java
C:\Java\Excep>

例外クラスの利用

では、準備が整いましたので、 UserList クラスをこれらの例外を throw するように編集します。

UserList.java:

class UserList {
	private String[] users;
	void setUsers(String[] args) {
		// 配列の参照の値の代入
		users = args;
	}
	String[] getUsers() throws NullUsersException {
		if (users.equals(null)) {
			throw new NullUsersException();
		}
		return users;
	}
	String getUser(int uid) throws UsersException {
		if (users.equals(null)) {
			throw new NullUsersException();
		} else if (uid < 0 || uid >= users.length) {
			UidOutOfBoundException excep
			    = new UidOutOfBoundException(users.length - 1);
			throw excep;
		}
		return users[uid];
	}
	int getUser(String user) throws UsersException {
		int uid = 0;
		if (users.length == 0) {
			throw new NullUsersException();
		} else {
			for (int i = 0; i < users.length; i++) {
				if (user.equals(users[i])) {
					uid = i;
					break;
				} else if (i == users.length - 1) {
					UserNotAuthorizedException excep
					    = new UserNotAuthorizedException();
					excep.setName(user);
					throw excep;
				}
			}
		}
		return uid;
	}
}

UsersList クラスの private ではないインタフェース部分を編集したので、このクラスをインスタンス化するコントロールクラスの方も編集します。

class UserTest {
	public static void main(String[] args) {
		UserList obj = new UserList();
		obj.setUsers(args);
		try {
			System.out.print("sugai -> ");
			System.out.println(obj.getUser("sugai"));
			System.out.print("10 -> ");
			System.out.println(obj.getUser(10));
		} catch (UsersException e) {
			System.out.println("");
			System.out.println(e);
			return;
		}
	}
}

コンパイルして実行します。コマンドライン引数がユーザ名の配列になります。引数を与えないで実行した場合は、ユーザが定義されていないので、例外 NullUsersException が発生するはずです。

C:\Java\Excep>javac UserTest.java
C:\Java\Excep>java UserTest
sugai ->
NullUsersException: ユーザが定義されていません。
C:\Java\Excep>

引数を与えても、対応するユーザが存在しなければ UserNotAuthorizedException が発生するはずです。

C:\Java\Excep>java UserTest root team01 team02
sugai ->
UserNotAuthorizedException: このユーザは認証されません。
C:\Java\Excep>

さらに、配列のインデックスを UID としてユーザ名をゲットできるはずですが、 UID が配列の要素数を超えたり、負数だったりすれば、 UidOutOfBoundException が発生するはずです。

C:\Java\Excep>java UserTest root team01 team02 sugai
sugai -> 3
10 ->
UidOutOfBoundException: UID の範囲は0から3です。
C:\Java\Excep>


Copyright © 2001 SUGAI, Manabu. All Rights Reserved.