進歩についていけない焦りを抱えた50代が、

若手のコードを理解できるようになることを目標に、Java7以降を一から学び直す記録です。
ラベル 例外処理 の投稿を表示しています。 すべての投稿を表示
ラベル 例外処理 の投稿を表示しています。 すべての投稿を表示

2026年2月11日水曜日

【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の再スローは地味だ。

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

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

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

【Java進化史 第27回】Java9でSetとMapにも of() が? 〜 なんじゃこりゃ、の続き 〜

前回、こんなコードで手が止まった。 List<String> names = List.of("Tanaka", "Sato", "Suzuki"); List.of() 。 変更できないリストを、一...