Javaでfinal変数が呼ぶ側に埋め込まれる理由

このタイトルはあまり正確じゃない。
正確にはfinal宣言と同時に値が定義された変数である。
Javaではfinal宣言と同時に値が定義されるかされないかで変数の挙動が変わってくる。
たとえば、
class A {
    public static final int a = 12345;
    public static final int b;

    static {
        b = 67890;
    }
}
上記のような場合、aはコンパイル時に値が決定する。これがいわゆる"定数(constant)"でbの場合は実行時にstaticイニシャライザが実行されるまで値が決定されない。
これはいわゆる一度だけ初期化可能な変数(readonly)だ。

ここまでは問題ないし、次もJavaプログラマならよく知っているだろう。

class B {
    public int addA() {
        return A.a + A.b;
    }
}
この場合、A.aはクラスBに埋め込まれてしまう。そのため、aの値を変更した場合、クラスAだけでなく、A.aを参照しているクラス、この場合はクラスBまで再コンパイルが必要となる。
これを嫌ってbのように宣言と同時に初期化せずにstaticイニシャライザで初期化しているコードもある。

なぜ、こんな仕様になっているんだろうか?
参照している側に埋め込まずに実行時にクラスAに参照しにいく仕様ではダメだったのだろうか?
パフォーマンスの問題だろうか?

結論を言ってしまえば、switch文である。
switch (x) {
    case A.a :
        ...
}
は問題ないけど
switch (x) {
    case A.b :
        ...
}
はコンパイルエラーになってしまうのだ。

これはなぜか?
まず、コンパイル時、実行時ともにcaseの値が重複しないことが保証されなければならない。
また、Javaのswitch文はJVMのlookupswitchかtableswitchバイトコードにコンパイルされるけど、Javaに限らず、通常switch-caseではジャンプテーブルが生成されることが多い。
この場合もcaseの値がコンパイル時と実行時で異なってしまうと都合が悪い。

そんな訳で定数は参照しているクラスに埋め込まれてしまうのだ。

javac -Xlint

普段はEclipseとかIDEを使っている人も多いと思うけど、javacコマンドでコンパイルするときに警告を最大限出してほしかったりする。
OracleのJDKであればjavacに-Xlintオプションを付けることによって、警告が出力される。

正規表現のデバッグ

正規表現も複雑になってくるとデバッガでステップ実行のようなことをしたくなってくることがある。
そんなときはPerlのデバッガを使うといい。

perlの起動時にオプションとして-Mre=debugもしくは-Mre=debugcolorを付けると
実行時に生成された正規表現オブジェクトの内容とマッチング経過が表示される。

例えば、"[tD]o\sBe\sDo"という正規表現を"to Be is to Do to Do is to Be Do Be Do Be Do"に適用すると
以下のように出力される。

$ perl -Mre=debug -e 'qq/to Be is to Do to Do is to Be Do Be Do Be Do/ =~ /[tD]o\sBe\sDo/'

Compiling REx "[tD]o\sBe\sDo"
Final program:
   1: ANYOF[Dt][] (12)
  12: EXACT <o> (14)
  14: POSIXD[\s] (15)
  15: EXACT <Be> (17)
  17: POSIXD[\s] (18)
  18: EXACT <Do> (20)
  20: END (0)
anchored "Be" at 3 (checking anchored) stclass ANYOF[Dt][] minlen 8 
Guessing start of match in sv for REx "[tD]o\sBe\sDo" against "to Be is to Do to Do is to Be Do Be Do Be Do"
Found anchored substr "Be" at offset 3...
start_shift: 3 check_at: 3 s: 0 endpos: 1 checked_upto: 0
Does not contradict STCLASS...
Guessed: match at offset 0
Matching REx "[tD]o\sBe\sDo" against "to Be is to Do to Do is to Be Do Be Do Be Do"
   0 <> <to Be is t>         |  1:ANYOF[Dt][](12)
   1 <t> <o Be is to>        | 12:EXACT <o>(14)
   2 <to> < Be is to >       | 14:POSIXD[\s](15)
   3 <to > <Be is to D>      | 15:EXACT <Be>(17)
   5 <to Be> < is to Do >    | 17:POSIXD[\s](18)
   6 <o Be > <is to Do t>    | 18:EXACT <Do>(20)
                                  failed...
  24 <o is > <to Be Do B>    |  1:ANYOF[Dt][](12)
  25 < is t> <o Be Do Be>    | 12:EXACT <o>(14)
  26 <is to> < Be Do Be >    | 14:POSIXD[\s](15)
  27 <s to > <Be Do Be D>    | 15:EXACT <Be>(17)
  29 <to Be> < Do Be Do >    | 17:POSIXD[\s](18)
  30 <o Be > <Do Be Do B>    | 18:EXACT <Do>(20)
  32 <Be Do> < Be Do Be >    | 20:END(0)
Match successful!
Freeing REx: "[tD]o\sBe\sDo"

出力内容の1〜9行目はコンパイルされた正規表現オブジェクトがどのような
10行目以降は実際に文字列に対してマッチングをしていく経過を表している。
ステップ実行とまではいかないが、十分なトレース情報が出力されている。
まず"Be"を検索しにいき(12行目)、そこから3文字戻り、マッチングを続けるが(11〜22行目)、
一度失敗し(23行目)、再度24文字目からマッチングを実行し(24〜30行目)、
マッチングに成功している(31行目)ことがわかる。

あくまで、Perlの実行時の動作なため、別の言語/処理系で同じ動作になる保証はないが、
別の処理系の動作のヒント程度にはなるのではないだろうか。

JDBC 4.0の例外

JDBC 4.0からは以下のSQL例外が追加されている。
SQLRecoverableException
SQLTransientException

SQLRecoverableExceptionはDBとのコネクションを一度クローズして再取得すれば、回復できる可能性がある例外。

SQLTransientExceptionは同じ処理を再実行すれば、回復できる可能性がある例外。

これらをうまくハンドリングすれば即時異常終了とリトライ処理を使い分けることができそうだ。