せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

チェック例外はコンパイルをすり抜ければOK

チェック例外でもコンパイルさえ誤魔化せばなんとでもなる。
その証明をしてみます。

こんなメソッドがあって

public class Employee {   
    public String getMessage(){
        throw new RuntimeException();
    }
}

こんな呼び出しメソッド(別クラス)があります。

public class EmpMain {
    public static void main(String[] args) {
        Employee employee = new Employee();
        employee.getMessage();
    }
}

コンパイルエラーは当然ありません。
実行したら正常に終了します。

ここで、最初のEmployeeクラスを以下のように修正します。

public class Employee {   
    public String getMessage() throws Exception {
        throw new Exception();
    }
}

当然、呼び出し側のメソッドはコンパイルエラーになります。
でもEmployeeクラス自体はコンパイル可能です。
じゃあ新しいEmployeeクラスを古いバイトコードから呼び出したらどうなるか。

> java EmpMain
Exception in thread "main" java.lang.Exception
    at byteread.Employee.getMessage(Employee.java:9)
    at byteread.EmpMain.main(EmpMain.java:8)

正常に実行できました。
ソースではコンパイルエラーになりますが、バイトコードでは問題がないことがわかりますね。

ちなみに逆のパターンだとどうでしょう。
employee.getMessage();がIOExceptionをスローしてくるのであれば、コンパイルは正常に終了します。

public class EmpMain {
    public static void main(String[] args) {
        Employee employee = new Employee();
        try {
            employee.getMessage();
            System.out.println("正常終了");
        } catch (IOException e) {
            System.out.println("IOEcxeption発生!");
        }
    }
}

しかし、Employeeクラスが修正され、getMessageメソッドがスローしなくなります。 そうするとソースコードはコンパイルエラーですが、バイトコードだけなら正常に実行できます。

ソースコード互換≠バイトコード互換ということです。