連載
» 2011年12月20日 00時00分 UPDATE

【改訂版】Eclipseではじめるプログラミング(24):Javaの例外処理で知らないと損する7つのテクニック (1/3)

これからプログラミングを学習したい方、Javaは難しそうでとっつきづらいという方のためのJavaプログラミング超入門連載です。最新のEclipseとJava 6を使い大幅に情報量を増やした、連載「Eclipseではじめるプログラミング」の改訂版となります(この回と前回のみ、別連載「EclipseでJavaに強くなる」の改訂版です。今回は第4回Javaの例外のテクニックを知る」の改訂版です)

[小山博史,株式会社ガリレオ]

 前回の「プログラマの宿命! 例外とエラー処理を理解する」では、Javaにおける例外の用途と基本的なコードの書き方、例外が発生するさまざまなケースについて理解しました。

 今回は、独自に例外を定義する方法や、ちょっとした例外のテクニックを紹介します。

【1】Eclipseで独自の例外クラスを定義するには

 独自の例外を定義する場合の基本は、java.lang.Exceptionを継承する例外クラスを定義することです。ここではsample24.SampleExceptionというクラスを作成してみましょう。Eclipseで例外クラスを定義するには下記のような手順になります。あらかじめsample24パッケージを作成しておいてください。

  1. [ファイル]→[新規作成]→[クラス]で[新規Javaクラス]ダイアログを表示
  2. パッケージへ「sample24」、クラス名へ「SampleException」を入力
  3. [スーパークラス]の[参照]で[スーパークラスの選択]ダイアログを表示
  4. 「Exception」と入力し[OK]ボタンをクリック
  5. mainメソッドを生成していない設定になっていることを確認して[終了]
画面1 [新規Javaクラス]ダイアログ 画面1 [新規Javaクラス]ダイアログ

 SampleExceptionクラスを作成したら、次のようにコーディングを完成させてください。

package sample24;
public class SampleException extends Exception {
    private static final long serialVersionUID = 1L;
    private int code;
    public SampleException(int code, String message) {
        super(message);
        this.code = code;
    }
    public int getCode() {
        return code;
    }
}

 ここでは、サンプルなのでcodeフィールドを用意しました。こういったフィールドを用意しておけば、独自のエラーコードを設定して、問題の切り分けがしやすいエラーメッセージを出力できます。

「serialVersionUID」フィールドとは

 なお、「serialVersionUID」というフィールドについては、Exceptionクラスをextendsしたクラスはシリアライズ可能なクラスとして、このフィールドを持つようにするのがいいため、用意しています。ここでは、こう書いておけばEclipseで警告が出ないと覚えておけばいいでしょう。

特別なフィールドを持たない例外クラスを定義するには

 どんな例外が発生したかを例外クラスのだけで表現することも多いので、特別なフィールドを持たない例外クラスを定義することもあるでしょう。そういった場合は、次のSampleException2のようなクラスを定義すれば十分です。

package sample24;
public class SampleException2 extends Exception {
    private static final long serialVersionUID = 1L;
    public SampleException2(String message) {
        super(message);
    }
}

【2】「throw」「throws」で例外を「投げる」には

 次に、この例外を「投げる」メソッドを持つクラスを作成します。メソッドでは、どんな例外を投げるか宣言する必要があるので、キーワード「throws」を使って投げる例外クラスを記述します。

例外を投げるサンプルクラス

 ここでは、名前とパスワードというユーザー情報をUserInfoクラスで表現し、ユーザー情報のリストをフィールドusersで持つSampleUserListクラスを用意します。

 このクラスのメソッドとして、nameとpasswordをパラメータとするloginメソッドを作成しますが、例外が発生した場合にはSampleExceptionとSampleException2を投げるようにthrowsをメソッドへ付けます。

package sample24;
public class SampleUserList {
    class UserInfo {
        private String name;
        private String password;
        public UserInfo(String name, String password) {
            this.name = name;
            this.password = password;
        }
        public String getName() { return name; }
        public String getPassword() { return password; }
    }
    private java.util.List<UserInfo> users = 
        new java.util.ArrayList<UserInfo>();
  
    public SampleUserList() {
        users.add(new UserInfo("Akira", "777"));
        users.add(new UserInfo("Jacky", "*"));
    }
  
    public boolean login(String name, String password)
    throws SampleException, SampleException2 {
        for (UserInfo user : users) {
            if ("".equals(name.trim())) {
                throw new SampleException(1, "ログインに失敗しました。");
            } else if ("".equals(password.trim())) {
                throw new SampleException(2, "ログインに失敗しました。");
            }
            if (user.getName().equals(name)) {
                if (user.getPassword().equals("*")) {
                    throw new SampleException2("ログインに失敗しました。");
                } else if (user.getPassword().equals(password)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
}

 メソッドの中では例外を投げる条件が満たされているときに、キーワード「throw」を使って例外を投げます。普通は例外のインスタンスを新規に生成して投げます。

 ここでは、SampleExceptionの例外を投げる条件は、nameの先頭と最後の空白を省略した結果が空文字列である場合か、passwordの先頭と最後の空白を省略した結果が空文字列の場合としました。このとき、どちらが原因となって例外が発生したのか分かるようにSampleExceptionのcode値を変えています。

 また、nameに対応するpasswordに「*」という文字列が設定されている場合は、そのnameが無効になっていると想定して、SampleException2の例外を投げるようにしています。

例外を受け取るサンプルクラス

 SampleUserAppクラスを使用して動作するプログラムは次のようになります。SampleUserAppクラスのloginメソッドが投げるSampleExceptionとSampleException2をcatchで受け取るようにtry文を記述しています。処理が実行されている順番が分かるように、すべて標準エラー出力へメッセージを出力しています。

package sample24;
public class SampleApp {
    public static void main(String[] args) {
        String[] users = { "Sara", "Akira", "Akira", "Jacky", "" };
        String[] passwords = { "", "777", "111", "abc", "xyz" };
        SampleUserList sample = new SampleUserList();
        for (int i = 0; i < users.length; i++) {
            try {
                System.err.print("i=" + i + ":");
                boolean isLogin = sample.login(users[i], passwords[i]);
                if (isLogin) {
                    System.err.println("ログインに成功しました。(" + users[i] + ")");
                } else {
                    System.err.println("ログインに失敗しました。");
                }
            } catch (SampleException e1) {
                e1.printStackTrace();
                System.err.println("code[" + e1.getCode() + "]");
            } catch (SampleException2 e2) {
                e2.printStackTrace();
            }
            System.err.println("");
        }
    }
}

例外を投げるサンプルの実行結果

 これを実行すると、画面2のようになります。

画面2 実行結果 画面2 実行結果

 nameが「Sara」でpasswordが半角空白の文字列だと、SampleUserAppクラスのloginメソッドはSampleExceptionを投げるので、それをキャッチしたcatch節の処理が実行されます。この結果スタックトレースが出力された後、codeの値である2が出力されています。

 次に、nameが「Akira」でpasswordが「777」の場合は正しい情報であるため例外は投げられずに正常に処理が終了しています。

 次に、nameが「Akira」でpasswordが「111」の場合は正しいパラメータを渡しているためパスワードが一致しない結果となるだけで例外が発生しません。次のname「Jacky」はパスワードが「*」で無効となっているユーザーであるため、SampleException2の例外が発生します。

 最後は、nameが「""」であるため、SampleExceptionの例外が発生しています。このように、意図したとおりに例外が投げられて、それをキャッチして処理が行われていることが分かるはずです。

       1|2|3 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

Touch Barという新UIを得た「MacBook Pro」、プレゼント!

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。