[???] /
[Java FAQ] / [S018]
S018: 例外処理 - exception
[S018 Q-01]
例外処理って何ですか?
[S018 A-01]
エラーなど不測の事態に対応するための機構です。
「特別な値を return させて if 文で処理する」方法ではなく、
try ... catch 構文や throw, throws 節により、プログラム本来の
流れとは別のコードを記述します。
例えば、指定されたファイルを開くプログラムを考えてみましょう。
このとき、ファイルにアクセスできないという不測の事態が発生するかもしれません。
そのような事態に陥ったときに、エラーメッセージを表示することとします。
これを例外処理を用いて記述すると、次のようになります。
String filename = "unhappy.txt";
java.io.FileInputStream fileInputStream = null;
try {
fileInputStream = new java.io.FileInputStream(filename);
} catch (java.io.FileNotFoundException e) {
System.out.println("ファイルが見つかりません。: "+filename);
}
[S018 Q-02]
Exception を throw するべきでしょうか、それとも特別な値を return するべ
きでしょうか?
[S018 A-02]
設計に依存します。
文字通り例外的な状態であれば例外を投げ、その状態を十分取り得るのであれば
その状態を表す値を返すように設計するのが良いでしょう。
例えば、 2 次元空間で 2 本の直線の交点(オブジェクト)を返すメソッドを
考えてみると、交点が存在しない場合は何を返すべきでしょうか。
このとき上のように考えれば、オブジェクトが存在しないことを表す null を返すのが
妥当であるということになります。
逆に例外を投げる場合の例を挙げると、正の整数を保持し int 型を return
するメソッドを持つオブジェクトは、もし値がセットされていない場合に特別
な値(例えば -1 )を返すよりも、何か値を保持していないことを表す例外を
投げた方が良いといえます。
[S018 Q-03]
throws 節なしのメソッドの中に throw 文があるのですが、これはなぜコンパ
イルエラーにならないのでしょうか?
[S018 A-03]
java.lang.Error および java.lang.RuntimeException のサブクラスの例外は
throws 節なしでも throw できることになっているからです。
[S018 Q-04]
Error、RuntimeException, Exception の違いは何ですか?
[S018 A-04]
例外の性質とそれに対するプログラマの対応が違います。
それぞれ次のような性質があり、対応をとります。
・Error
回復が困難または不可能なシステム上のエラーです。
プログラマは通常何もしません。また、throws 節に記述する必要も
ありません。ただし、プログラマはこれ以上、処理を続行できない場合
にのみ明示的に java.lang.Error のサブクラスを throw するべきです。
・RuntimeException
実行してみないと発生するかどうかわからない例外です。
プログラマは通常何もしません。また、throws 節に記述する必要も
ありません。ただし、プログラマは例外を catch して処理を続行する
ことができます。
・Exception
プログラミング時に発生するかどうかがわかる例外です。
プログラマは try ... catch 構文か throw, throws 節を記述しなければなり
ません。
S018-03 も参照して下さい。
[S018 Q-05]
絶対起きることのない例外を catch せざるを得ないときそこで何をさせるべ
きでしょうか?
[S018 A-05]
Error または RuntimeException を throw すると良いでしょう。
「絶対にその例外が起こらない」というのは、もしかすると
プログラマの勘違いであるかもしれないからです。もし Error または
RuntimeException が throw されれば、そのような思い込みを気付かせてくれます。
悪い例
try {
newpage = new URL("http;//java.sun.com/");
// ^
} catch (MalformedURLException e) {
}
良い例
try {
newpage = new URL("http;//java.sun.com/");
} catch (MalformedURLException e) {
throw new RuntimeException(e.toString());
}
[S018 Q-06]
finally 節はどのように使えばいいのですか?
[S018 A-06]
例外があろうとなかろうと終了処理を確実に実行しなければならないときに使います。
例えば、次のようなプログラムがあったとします。
try {
Thread.sleep(100000);
System.out.println("目覚しが鳴った");
} catch (InterruptedException e) {
System.out.println("電話が鳴った");
} finally {
System.out.println("起きた");
}
これを実行すると、例外が発生しない場合は
目覚しが鳴った
起きた
のように出力されます。例外が発生すると、
電話が鳴った
起きた
のようになります。finally 節は例外の有無にかかわらず実行されるため、
リソースを必ず解放したいときにも使います。
[S018 Q-07]
完成したプログラムで catch ブロックに、e.printStackTrace() が入って
いてはいけないのですか?
[S018 A-07]
本当にスタックトレースを出力する必要がある場合を除き、入れないほうがいい
でしょう。
e.printStackTrace() の出力をユーザが読んで対処できないケースが大多数なので、
完成品には含めないほうがいいでしょう。例外が起り得るのであれば適切な処理を行い、
起り得ない例外であれば、S018-05 に従って、Error または RuntimeException
を throw しましょう。スタックトレースの出力が必要になるのは、設計によりますが、
たとえば、コンポーネントやフレームワークなどの製品で不具合が発生したときの調査
のために入れておくなどがあります。
[S018 Q-08]
コンストラクタで例外を投げるのは問題がありますか?
[S018 A-08]
インスタンス変数の初期化が正しく行われない問題があります。
生成に失敗したインスタンスが参照されることはないので、通常は実害は
ほとんどありません。
[S018 Q-09]
throws 節の例外を増やしてメソッドをオーバーライドしたいのですが、
可能ですか?
[S018 A-09]
S011-08 を参照して下さい。
contributor: morphylu
コメントの送り先 Java FAQ BBS