2007年10月15日月曜日

例外

例外 = フローの中のエラー


例外の種類

チェック例外     : Exception クラスを継承する例外(RuntimeException を除く)
Runtime 例外     : RuntimeException とそれを継承する例外
Error     : Error クラスとそれを継承する例外

Runtime 例外と Error は非チェック例外となります。
_______________

try - catch - finally ブロック

チェック例外は try - catch - finally ブロックで処理します。
finally ブロックは任意ですが、例外が発生してもしなくても必ず実行されます。

public class Sample {
    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.func();
    }

    /* dangerousMethod を try - catch - finally で処理 */
    void func() {
        try {
            dangerousMethod();
        } catch (Exception e) {
            System.out.println("例外が発生しました");
        } finally {
            System.out.println("必ず実行される処理");
        }
    }

    /* 例外が発生する可能性を throws キーワードで宣言 */
    void dangerousMethod() throws Exception {
        throw new Exception();
    }
}
_______________

例外には「処理か宣言」の原則があります。
例外の発生する可能性のあるメソッドで「処理か宣言」のどちらかを行います。

<処理>
    try - catch ブロックで囲む。
<宣言>
    throws キーワードで発生する可能性のある例外を宣言する。
_______________

throw キーワード

throw キーワードで例外を投げることができます。
try - catch ブロックで例外をキャッチしてさらにそのメソッドの呼び出し元に例外を投げることもできます。

    void func() throws Exception {
        try {
            dangerousMethod();
        } catch (Exception e) {
            throw e;
        }
    }

こうすると呼び出し元でさらに try - catch する必要があります。
_______________

複数の例外を処理する際の注意

複数の例外を処理する際は、例外クラスの継承関係の下位にある例外から順番に処理します。
継承関係の上位にある例外を try - catch ブロックで先に処理するとコンパイルエラーになります。

    void func() {
        try {
            dangerousMethod();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    void dangerousMethod() throws IOException {
        throw new IOException();
    }

Exception を先に catch ブロックに書くと次の IOException のキャッチブロックは到達不能になり、コンパイル不可なります。
_______________

RuntimeException

RuntimeException は非チェック例外ですが、Exception クラスを継承しているので try - catch ブロックで処理することができます。
RuntimeException は throws キーワードで RuntimeException の発生の可能性を宣言する必要はありません。

    void func1() throws IOException {
        throw new IOException();
    }
    void func2() {
        throw new RuntimeException();
    }
_______________

finally ブロック

finally ブロックは例外が発生してもしなくても処理を実行するので
ストリームの切断など確実にしておきたい処理を記述しておくとよいでしょう。
しかし、下記のコードはコンパイルできません

public class Sample {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("C:/test.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            br.close();
        }
    }
}

br.close(); の部分を try - catch ブロックで囲む必要があります。

0 件のコメント: