Ch6. 例外処理

マルチキャッチ

catchする例外クラスを複数並べて記述できる。 ただし、並べて書く際は継承関係のある例外クラスを記述できない。

public class ExceptionSample {
    public static void main(String[] args){

        try{
            throw new SubSubException();
        }catch (Exception | SubSubException e){ //Types in multi-catch must be disjoint: 'SubSubException' is a subclass of 'java.lang.Exception
            System.out.println("Exception");
            e = null; //Types in multi-catch must be disjoint: 'SubSubException' is a subclass of 'java.lang.Exception
        }catch (Throwable e){
            e = null;
        }
    }
}
class SubException extends Exception{
}

class SubSubException extends SubException{
}

また(意図は不明だが)マルチキャッチでキャッチした参照変数でだけ、final状態となり変数の上書きが禁じられる。

rethrow

Java SE6までは)throwsで明示した例外クラスを一度catchしてから再度rethrowする場合にcatch節にその例外クラスを設定する必要があった(つまり上位クラスの例外クラスではrethrowできなかった)。

具体的には以下のようなことになる。

public class ExceptionThrowsSample {
    public static void main(String[] args) throws MySubException{
        new ExceptionThrowsSample().OriginalMethod();
    }
    void OriginalMethod() throws MySubException{
       try{
           System.out.println("");
           throw new MySubException();
       }catch (MyException e){ //上位クラスでCatchしている。
           throw e;
       }
    }
}

class MyException extends Exception{
}

class MySubException extends  MyException{
}

オーバーライドしたメソッドのthrows

オーバーライドしたメソッドでは、必ず親クラスと同じthrowsを設定しないといけないわけではない。 throwsを設定しないことも可能で、その場合オーバーラードしたメソッドを呼び出すときは例外処理が不要になる。

ただし、throwsを設定する場合は下記の例外しかthrows出来ない。 * 親クラスのthrowsで設定した例外クラスのサブクラス * RuntimeExceptionのそのサブクラス

import java.io.EOFException;
import java.io.IOException;
import java.sql.SQLException;

class ParentalClass{
    public void method() throws IOException{
    }
}
public class OverrideThrows extends ParentalClass{
    public static void main(String[] args){
        OverrideThrows obj = new OverrideThrows();
        obj.method();
        ParentalClass obj2 = new OverrideThrows();
        obj2.method();//'Unhandled exception: java.io.IOException'
    }

    public void method(){
    }
}

class ChildClass extends OverrideThrows{
    public void method() throws SQLException {//'method()' in 'ChildClass' clashes with 'method()' in 'OverrideThrows'; overridden method does not throw 'java.sql.SQLException'
    }
}

class ChildClass2 extends ParentalClass{
    public void method() throws EOFException {
    }
}

class ChildClass3 extends ParentalClass{
    public void method() throws SQLException { //'method()' in 'ChildClass3' clashes with 'method()' in 'ParentalClass'; overridden method does not throw 'java.sql.SQLException'
    }
}

try-with-resources

今までfinalブロックに書いていた(DBコネクションなどの)リソースの終了処理を勝手にやってくれる仕組み。 tryの括弧の中にブロックが終わるときに終了したいリソースを書いておく。

import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import java.io.Closeable;

public class WithResources {
    public static void main(String[] args){
        try(DbConnectionA a = new DbConnectionA(); DbConnectionB b = new DbConnectionB()){
            System.out.println("end of try block");
        }finally {
            System.out.println("finally Block");
        }

    }
}

class DbConnectionA implements AutoCloseable{
    public void close() {
        System.out.println("CloseA");
    }
}

class DbConnectionB implements Closeable {
    public void close() {
        System.out.println("CloseB");
    }
}

//end of try block
//CloseB
//CloseA
//finally Block

抑制された例外

try-with-resourcesを使う場面だと「tryの中でも、closeの中でも例外が発生する」ということが起こりうる。 この場合、closeの中で発生された例外は「抑制された」例外として扱われ、catch節のエラー変数では(getSuppressedメソッドを利用しないと)確認することが出来ない。

getSuppressedメソッドを使うと、発生した全てのエラーがthrowableクラスの配列として返却されるのでcloseメソッドで発生した分を含めて全て確認することが出来る。 また、エラーオブジェクトに任意の例外を追加するメソッドも提供されている。

import java.io.Closeable;
import java.util.Arrays;

public class WithResources {
    public static void main(String[] args){
        try(DbConnectionA a = new DbConnectionA(); DbConnectionB b = new DbConnectionB()){
            System.out.println("end of try block");
            throw new ArrayIndexOutOfBoundsException();
        }catch(Throwable e){
            e.addSuppressed(new StackOverflowError());
            System.out.println(e);
            Arrays.stream(e.getSuppressed()).forEach(System.out::println);
        }
        finally {
            System.out.println("finally Block");
        }
    }
}

class DbConnectionA implements AutoCloseable{
    public void close() {
        System.out.println("CloseA");
        throw new RuntimeException();
    }
}

class DbConnectionB implements Closeable {
    public void close() {
        System.out.println("CloseB");
        throw new ArrayStoreException();
    }
}

//end of try block
//CloseB
//CloseA
//java.lang.ArrayIndexOutOfBoundsException
//java.lang.ArrayStoreException
//java.lang.RuntimeException
//java.lang.StackOverflowError
//finally Block

アサーション

JVMの実行時オプションに-eaを渡すと利用できる。 アサーションの式がfalseを返した場合、指定したメッセージを表示することが出来る。

-eaオプションを指定しなければこの行は無視してくれるため、例えfailしても実行時に警告等は出ない。

public class AssertionSample {
    public static void main(String[] args){
        int variable = 100;
        assert variable < 99 : "variable is : " + variable;//'Exception in thread "main" java.lang.AssertionError: variable is : 100'
    }
}