例外の基本は「コンパイル時にチェックされる例外」になります。この例外を使えば、例外が発生した後にアプリケーションが引き続き処理を続行できるようになります。例えばWebブラウザを使ってあるURLへアクセスしたところ、ネットワークの問題でアクセスできなかった場合に、Webブラウザが停止してしまって再起動が必要となるのでは使い勝手が悪いはずです。そのURLへのアクセスをあきらめて、ほかのURLへアクセスできるように、Webブラウザは停止せずに引き続き処理を続行するようにプログラムを作成することになるでしょう。こういった場合に「コンパイル時にチェックされる例外」は役に立ちます。Javaではこの例外をjava.lang.Exceptionクラスとして表現しています。このクラスのサブクラスとしては、入出力処理における例外を表すjava.io.IOExcepitonや、データベース処理における例外を表すjava.sql.SQLExceptionがあります。
それでは、All-In-One Eclipseを起動して「コンパイル時にチェックされる例外」を使用するプログラムを作成してみましょう。mainメソッドを持つ次のSample310クラスを新規に作成してください。mainメソッド内の処理には前回のプログラムSample210クラスのmainメソッド内と同じコードを記述します。今回はSample210クラスのmainメソッドに付けていた「throws java.lang.Exception」がなくなっている点に気を付けてください。
Simport java.io.BufferedReader; import java.io.InputStreamReader; public class Sample310 { //----- ここから public static void main(String[] args) { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Input name:"); String name = in.readLine(); in.close(); System.out.println("Hello, "+name); } //----- ここまで }
さて、このようにコーディングすると、Eclipseでは「in.readLine()」と「in.close()」に赤い下線が引かれて、エラーがあることが分かります。これは、これらのメソッドを呼び出すと中でエラーが発生する可能性があるので例外を捕捉(キャッチ)するコードを追加する必要があることを意味しています。例外を捕捉するコードを記述するにはtry文を使います。
細かい説明をする前に、Eclipseの機能を使ってtry文を追加してみましょう。エディタに表示されているSample310.javaの「in.readLine()」の行で左側に表示されているバツ印付きのランプをマウスの左ボタンでクリックします。すると修正方法を選択するポップアップメニューが表示されますから、そこから「try/catchで囲む」を選んでマウスで左クリックしてください。自動的に「in.readLine();」を囲むようにtry文が追加されます。また、java.io.IOExceptionという例外の型がimportされます。
「in.close()」の行でもjava.io.IOExceptionの例外が発生する可能性があることからエラーとなっています。この処理は後述するように特別なので、finally節というものを次のように追加してその中へ入れます。また、「in.readLine()」の行で行ったのと同様にして例外をキャッチするコードも追加します。System.out.println("Hello, "+name)の行については、nameの初期化がされていないことが原因でエラーが出ていますので、これもtry文の中へ入れて初期化された場合にのみ使われるようにします。
public class Sample310 { //----- ここから public static void main(String[] args) { java.io.BufferedReader in = new java.io.BufferedReader( new java.io.InputStreamReader(System.in)); System.out.print("Input name:"); String name; try { name = in.readLine(); System.out.println("Hello, "+name); } catch (java.io.IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (java.io.IOException e) { e.printStackTrace(); } } } //----- ここまで }
以上のようにEclipseを使っている場合は、まずは行いたい処理をとにかくコーディングしてしまいましょう。赤い下線が表示され、try文を使っていないことからエラーが発生していると分かった場合には、上記のような方法でtry文を自動生成すると簡単に例外へ対応するコードを記述することができます。
本稿のサンプルでは例外をキャッチしたときに、エラー発生時にどのようなメソッドがどんな順番で呼ばれてエラーとなったのかを追跡できるように「e.printStackTrace();」というスタック情報を出力するコードを書いていますが、通常は適切なエラーメッセージを出力したり、ログ情報の出力をしたりするコードを記述します。また、文法的には空行とすることもできますが、プログラム上の例外的な何かが発生しているわけですから、それに対して有効な何らかの対応をするコードを記述するようにしましょう。
次はこの例外へ対処するコードについて文法的に理解をしましょう。Sample310.javaでコーディングしたような「例外へ対処するコード」はtry文といいます。try文は次のように書きます。
try { 行いたい処理の文 } catch (例外型1 e1) { 例外型1の例外が発生した場合に行いたい処理の文 } catch (例外型2 e2) { 例外型2の例外が発生した場合に行いたい処理の文 } finally { 例外が発生してもしなくても必ず行う処理の文 }
tryの直後のブロックをtryブロック、finallyの直後のブロックをfinallyブロックといいます。tryブロックの直後にはcatch節を含めることができます。catch節は例外ハンドラと呼ばれることもあります。catch節では「(例外型1 e1)」のように例外パラメータを1つだけ指定する必要があります。このパラメータはcatch節の直後にあるブロック内で有効となります。例外パラメータの型はjava.lang.Throwableのサブクラスである必要があります。
注意
例外パラメータの型は、文法的にはjava.lang.Throwableクラスか、このクラスを継承したクラスであれば良いのですが、実際にはjava.lang.Throwableクラスを指定することはありません。このクラスを指定すると、後述するキャッチすべきではない「java.lang.Error」もキャッチすることになるからです。
tryブロック、つまり「行いたい処理の文」の中で例外が発生するメソッドがある場合は、その例外に応じてcatch節を記述します。「行いたい処理の文」は複数の文を書けるので、キャッチする必要がある例外も複数あり得ます。このためcatch節は例外の型に応じて複数指定することができるようになっています。
finallyブロックは「例外が発生してもしなくても必ず行う処理」を記述するために使います。例えば、入出力ストリームを使用するプログラムでは、ある入出力ストリームを使ったら、その入出力ストリームを閉じるcloseメソッドを必ず呼び出す必要があります。これは、入出力ストリームはOSによって管理される資源(リソース)ですから、OSへ必ず使い始めることと、使い終わったことを知らせる必要があるからです。このため、入出力ストリームを使用している最中に例外が発生した場合でも、必ず終了処理であるcloseメソッドを呼び出す必要があるのです。Sample310クラスにおいて、「in.close();」の処理は特別だと書きましたが、こういった特別な事情があったので、finallyブロックの中へ入れたのでした。
Copyright © ITmedia, Inc. All Rights Reserved.