2006-04-05 [長年日記]

例外を吐くコンストラクタって [tech][java]

このプログラムは"null"が出力されるのか、"not null"が出力されるのか?直感的には"null"になりそうだが、out of order書き込みの可能性を考えると、一概にそうとは言えないかもしれない。

lethevert is a programmer - Java : コンストラクタで例外

経験的にはnullだ。
早速実験。

public class ExceptionalObject {
    public ExceptionalObject() {
        throw new RuntimeException();
    }

    public int intValue() {
        return 5;
    }
}
public class Object1 {
    public static void main(String[] args) {
        Object obj = null;
        try{
            obj = new ExceptionalObject(); //例外発生
        }catch(Exception e){}
        if (obj == null) {
            System.out.println("null");
        }else{
            System.out.println("not null");
        }
    }
}

結果は

null


次。

public class Object1 {
    public static void main(String[] args) {
        int i = 3;
        int j = 0;
        try{
            j = (i++) + (new ExceptionalObject()).intValue();
        }catch(Exception e){}

        System.out.println("i="+i);
        System.out.println("j="+j);
    }
}

int の +演算子は左結合のはずだから、(i++)が先に評価される。
でも+演算子の右で例外発生。+演算子も=演算子も評価されないはず。
では(i++)はどうなるのか。これが(++i)なら4だろうと想像できるのだけど、さて?
結果。

i=4
j=0

i++によるインクリメントはちゃんと実行されている。
へー。そうなんだ……。


余談。
RuntimeExceptionではない例外を吐くコンストラクタ。

public class ExceptionalObject2 {
    public ExceptionalObject2() throws java.io.IOException {
        throw new java.io.IOException();
    }
}

うわ。気持ち悪い*1

public class Object2 {

    ExceptionalObject2 obj = new ExceptionalObject2();
    static ExceptionalObject2 staticobj = new ExceptionalObject2();

    public Object2() {
    }
}

とか書けません。

public class Object2 {

    ExceptionalObject2 obj = null;
    {
        try {
            obj = new ExceptionalObject2();
        }
        catch (java.io.IOException e) {}
    }

    static ExceptionalObject2 staticobj = null;
    static {
        try {
            staticobj = new ExceptionalObject2();
        }
        catch (java.io.IOException x) {}
    }

    public Object2() {
    }
}

と書かざるをえない。ダサダサ。
というかコンストラクタでRuntimeExceptionじゃない例外を吐く様なものを、クラスやインスタンスの初期化で書くのがまずい。
そんなことになったら、どっか設計がおかしいと思って見直すべし、だなぁ。


追記

public class Object1 {
    public static void main(String[] args) {
        int i = 3;
        int j = 0;
        try{
            j = (i++) + (new ExceptionalObject()).intValue();
        }catch(Exception e){
            System.out.println("i="+i);
        }

        System.out.println("i="+i);
    }
}

ってどうなるんだ? と思った。

i=4
i=4

だった。catchに入る前に i++ によるインクリメントされてるってことか。

Palm TX買った! [palm]

英語デバイス初めて!
J-OS初めて!
ネットワークでHotSyncしたいのにマシン名が出てこない!
Linuxマシンの名前は出てくるのに?
初めてづくしだ〜。


ハードリセットだ〜。あはは〜。

*1 極端な形で書いたから気持ち悪いのであって、コンストラクタがIOExceptionなどをthrowするのは、java.ioパッケージなどでは当たり前の話。