2026年2月11日水曜日

【Java進化史 第8回】Java7 〜例外を“正確に投げ直せる”ようになった日〜

【Java進化史 第8回】Java7 〜例外を“正確に投げ直せる”ようになった日〜

昔、本当に例外処理ばかり書いていた。

正常処理より catch の方が長い。
そんなクラスも珍しくなかった。

とにかく捕まえる。
とにかく投げる。
とにかく throws を増やす。

そして気がつけば、メソッドの宣言はこうなる。


public void process() throws Exception

もう何でもありだ。

「結局、何が飛んでくるの?」

呼び出し側はこう書く。


try {
    process();
} catch (Exception e) {
    // で、何が来るの?
}

IOException?
SQLException?
それとも別の何か?

結局、process() を読む。
さらにその中で呼ばれているメソッドも読む。

これをカプセル化と呼べるのか。

メソッドのシグネチャを見れば契約が分かる。
それがオブジェクト指向の約束ではなかったのか。

だが現実は違った。

throws Exception は便利だった。

便利だが、それは「設計の曖昧さ」を広げていただけだった。

■ Java6までの“濁り”

例えば、こんなコード。


public void process() throws Exception {
    try {
        readFile();   // throws IOException
    } catch (Exception e) {
        throw e;
    }
}

readFile() は IOException しか投げない。

だが catch (Exception e) と書いた瞬間、
コンパイラはこう判断する。

「Exception が投げられる可能性がある」

だから throws Exception になる。

正確ではない。
広がっている。

そして、その広がりは呼び出し側へ伝染する。

設計が、少しずつ濁っていく。

■ Java7の“地味な革命”

Java7で導入されたのが、
precise rethrow(例外の再スローの型推論) だ。

同じコードでもこう書ける。


public void process() throws IOException {
    try {
        readFile();   // throws IOException
    } catch (Exception e) {
        throw e;
    }
}

一見、何も変わっていない。

だがコンパイラが変わった。

Java7はこう考える。

「tryブロックの中で、実際に投げられる例外型は何か?」

readFile() が投げるのは IOException だけ。

だから再スローされる型も IOException だけだと判断する。

その結果、


throws IOException

で済む。

例外が“正確になる”。

■ 何が嬉しいのか

  • throws が広がらない
  • APIが引き締まる
  • 呼び出し側が迷わない
  • シグネチャが契約として機能する

呼び出し側はこう書ける。


try {
    process();
} catch (IOException e) {
    // 何が来るか分かっている
}

読まなくていい。
追いかけなくていい。

契約が戻ってくる。

これは小さいが、本質的な改善だ。

■ それでも万能ではない

catch 変数を再代入すると、この推論は効かない。


catch (Exception e) {
    e = new Exception();  // 再代入すると従来通り広がる
    throw e;
}

コンパイラが追跡できる範囲でのみ働く。

魔法ではない。
だが思想は明確だ。

「正確に宣言せよ」

■ 例外はどこで処理するのか

  • 発生箇所 → 技術的例外をそのまま投げる
  • 中間層 → 無理に握りつぶさない
  • 最上位 → ログ、通知、終了判断

Java6時代、広がった throws Exception は、その責任を曖昧にした。

Java7のprecise rethrowは、例外を“適切な型で上に渡す”ことを助ける。

それはつまり、責任の所在を明確にすることだ。

■ あの頃の自分に言いたい

Java7の再スローは地味だ。

だが、例外に振り回されてきた世代にとっては、 設計を少しだけ取り戻すための機能だった。

派手な進化ではない。
だが、確かに“進化”だった。

地味だけど、確実に設計や実装の質を上げる「例外の再スローの型推論」。
こういう機能、好きだなぁ。

0 件のコメント:

コメントを投稿

【Java進化史 第10回】Java8 〜あのPermGenはどこへ消えた〜

【Java進化史 第10回】Java8 〜あのPermGenはどこへ消えた〜 昔、意味も分からず書いていたオプションがある。 -XX:MaxPermSize=256m 足りなければ増やす。 512m。 1024m。 それでも、死ぬ。 java.l...