プログラマの宿命! 例外とエラー処理を理解する【改訂版】Eclipseではじめるプログラミング(23)(1/3 ページ)

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

» 2011年11月01日 00時00分 公開
[小山博史株式会社ガリレオ]

プログラマの“宿命”、「例外」を究めよう!

 Javaでは、エラーへ対処する処理を記述するための仕組みとして「例外」というものがあります。データの入出力を伴うプログラムでは、基本的に例外を使ったプログラムを作成する必要がありますから、よく理解しておきましょう。

 また、この仕組みを使うと、エラーへ対応するプログラムを書くのがとても簡単になりますから、自分が作成するクラスへも積極的に組み込めるようになりましょう。

単純なエラーへ対応するプログラム

 プログラムでエラーが発生した場合の対処方法としては、どんな方法が考えられるでしょうか。単純なエラーに対応する場合には、メソッドの返却値を利用できます。

 例えば、CenterFrameクラスを作成し、このクラスへデスクトップの幅と高さを受け取って、ウィンドウをデスクトップの中央に配置するlocateToCenterメソッドを作成したとします。この場合、デスクトップのサイズがウィンドウのサイズよりも小さい場合はエラーとして処理を行わないことにします。このとき、中央へ配置する処理が行われた場合はtrueを返し、エラーが発生した場合にはfalseを返すことにします。

package sample23.app1;
public class CenterFrame extends javax.swing.JFrame {
    public CenterFrame() {
        this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    }
    public boolean locateToCenter(int width, int height) {
        if (width <= getSize().width || height <= getSize().height) {
            return false;
        }
        setLocation((width-getSize().width)/2, (height-getSize().height)/2);
        return true;
    }
}

 このメソッドの使用例は、次のCenterFrameMainクラスのようになります。デスクトップのサイズが1024x768の場合、fは800x600なのでデスクトップ内に収まるので表示しますが、f2は1600x1200なのでデスクトップ内に収まらないので表示しません。

 つまり、正常に処理が終了した場合は画面を表示しますが、エラーが発生した場合はエラーメッセージをコンソール画面へ出力して画面は表示しません。このようにlocateToCenterメソッドを使えば、メソッドの処理が正常に終了したのか、エラーが発生したのかを判定した処理が可能となります。

package sample23.app1;
public class CenterFrameMain {
    public static void main(String[] args) {
        CenterFrame f = new CenterFrame();
        f.setSize(800, 600);
        if (f.locateToCenter(1024, 768)) {
            f.setVisible(true);
        } else {
            System.out.println("800x600 Error");
        }
        CenterFrame f2 = new CenterFrame();
        f2.setSize(1600, 1200);
        if (f2.locateToCenter(1024, 768)) {
            f2.setVisible(true);
        } else {
            System.out.println("1600x1200 Error");
        }
    }
}

メソッドの返却値によるエラー対応の限界

 さてここで、CenterFrameクラスのlocateToCenterメソッドは正常終了したかどうかを返却するように定義できましたが、すべてのメソッドがこのようにできるわけではありません。このため、メソッドの返却値を使う方法には限界があります。

 例えば、デスクトップの中央へ画面を表示するための座標を取得できるメソッドを提供することになったとしたら、次のようなメソッドになるでしょう。

    public java.awt.Point getPointForLocateToCenter(int width, int height) {
        if (width <= getSize().width || height <= getSize().height) {
            return null;
        }
        return new java.awt.Point(
            (width-getSize().width)/2, (height-getSize().height)/2);
    }

 ここでは、返却値はjava.awt.Point型の座標なので、計算で問題が発生する場合にはnullを返すようにしています。これはつまり、このメソッドを使って取得した座標値を使う場合には、必ずnull判定をする必要があるということになり、エラー処理へ対応するためのコードが多くなるという問題につながります。

 これを避けるために、例えば(‐1, ‐1)という座標値を返却するようにメソッドを用意することもできますが、その場合はこのメソッドから返却される(‐1, ‐1)という座標値は特別な意味があるということをメソッドの使用者が知っている必要が出てきます。

 エラーの発生原因が1つしかないような単純な場合はこれでも良いのですが、「ファイルを開く」といった処理をしたときに、「指定したファイルがなくて開けなかった」のか、「アクセス権がなくて開けなかった」のか、「そのファイルを排他的に使っているプロセスがあるために開けなかった」のか、といったようにエラーを発生させる原因が複数ある場合にも対応しようとすると、メソッドを作成する側もメソッドを利用する側も、かなり多くのチェックコードをコーディングする必要が出てきてしまいます。

 ほかにもメソッドの返却値を使ったエラーの対処方法では、対応することが難しいことがあります。

 例えば、ハードウェアの故障などにより、即座にプログラムを停止する必要がある致命的なエラーが発生することはありますから、これに備えたプログラムの記述をプログラマへ強制させたいといった場合です。CenterFrameクラスのlocateToCenterメソッドについて、必ず成功か失敗かを判定するように強制したくても、次のようにプログラムがコーディングをした場合にコンパイラはエラーを出しません。

    CenterFrame f = new CenterFrame();
    f.setSize(800, 600);
    f.locateToCenter(1024, 768);
    f.setVisible(true);

 つまり、判定の強制をプログラムすることができません。この結果、プログラマのうっかりミスで、メソッドが返すエラーをチェックしないプログラムというのが簡単に入り込んでしまうわけです。

 Javaでは、こういった問題を解決するために、「例外」というメカニズムが用意されています。例外を使うと、メソッドがエラーコードを返したり、メソッドからのエラーコードをチェックしたりしなくても、メソッドの中でエラーが発生したことを簡単に捕捉して対応する処理を記述できます。

 Javaには、次の2種類の例外があるので、次ページから順番に見ていきましょう。また、例外と深い関係にある「java.lang.Error」クラスについても簡単に解説します。

コラム ExceptionとRuntimeExceptionとErrorの違い

java.lang.RuntimeExceptionはjava.lang.Exceptionのサブクラスなので、クラス体系上で見ると「2種類の例外がある」というわけではありません。ただし、性質が大きく異なるため、本稿では分けて解説します。

また、java.lang.Errorクラスはjava.lang.Exceptionクラスで表現される例外とは違いますが、java.lang.Errorとjava.lang.Exceptionは、どちらも「java.lang.Throwable」クラスを継承しているので、java.lang.Throwable型であるという点では同じであり深い関係があるといえます。


       1|2|3 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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