【Java進化史 第1回】Java7 - try-with-resourcesは何を変えたのか?
Java7は地味だと言われる。
だが、現場を救った機能がある。
それが try-with-resources だ。
■ 昔のclose地獄
Java6まで、リソースを扱うコードはこうだった。
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
何度これを書いただろう。
- close忘れ
- 二重try
- ネスト地獄
そして一番怖いのは、 close忘れによるDB接続リークだ。
Javaから接続しているDBコネクションが解放されず、 接続数がMAXに達する。
ある日突然、全体が止まる。
原因は、たった一行のclose忘れ。
実際に、トラブルの火種になり得る。
■ JDBCコネクションプールとの関係
「でも今はコネクションプールがあるから大丈夫では?」
確かに、最近の現場では HikariCPなどのコネクションプールを使うのが普通だ。
だが重要なのはここだ。
close()は“破棄”ではない。
プール利用時のclose()は、 接続を物理的に切断するのではなく、 プールへ「返却」しているだけだ。
つまり、close()を呼ばなければ、 プールに戻らない。
結果として、
- 接続が枯渇する
- 待ちが発生する
- 最悪、システム停止
try-with-resourcesは、 プール利用環境でも極めて重要なのだ。
■ 実務では自分で書かない?
正直に言うと、 DB接続処理などは共通部品化されていることが多い。
だから普段は、自分でcloseを書くことは少ない。
だが――
「ちょっとした検証コード」
「一時的なバッチ」
「ローカルでのテスト」
こういうときに、自分で書く。
そして、うっかりcloseを書き忘れる。
私はある。
■ Java7で何が変わったのか
try (FileInputStream fis = new FileInputStream("test.txt")) {
// 処理
} catch (IOException e) {
e.printStackTrace();
}
tryの丸括弧の中に「resource」を書く。
すると、ブロック終了時に自動でclose()が呼ばれる。
finallyは不要。
ネストも不要。
■ 名前の意味
try-with-resources。
直訳すれば、
「リソース付きtry文」。
リソース(=closeが必要なもの)を tryと一緒に宣言する。
だから、try with resources。
■ AutoCloseableとは何か
対象となるのは、 AutoCloseable を実装しているクラスだ。
つまり「close()メソッドを持つ型」。
- ファイル(FileInputStream / BufferedReader など)
- データベース(Connection / Statement / ResultSet)
- ソケット(Socket)
- ZipFile
- Scanner
JDK標準ライブラリの多くはAutoCloseableに対応している。
「closeが必要なものは大体いける」と思ってよい。
さらに、自作クラスでも実装できる。
class MyResource implements AutoCloseable {
public void close() {
System.out.println("closed");
}
}
これは単なる糖衣構文ではない。
リソース管理の統一ルールを作った機能なのだ。
■ Java6方式と混在しても動くのか?
結論から言えば、動く。
だが、保守性は確実に落ちる。
- 書き方が統一されない
- レビュー時の負担が増える
- ミスの温床になる
可能であれば段階的に置き換えるべきだ。
もちろん、 予算と時間が許せば。
だが新規コードでは、必ず使う。
■ まとめ
派手さはない。
ラムダのような衝撃もない。
だが、
try-with-resourcesは、 「書きやすくした機能」ではない。
事故を減らすための設計思想だ。
Javaは派手に変わることもある。
だが、本当に現場を救うのは、
こういう地味な進化かもしれない。
0 件のコメント:
コメントを投稿