JavaのAutoCloseableとかいうやつ
情報豊富で枯れたものが好きな私でも、さすがにJavaの開発では、そろそろJDK 7を使ってもいいんじゃないかと思い始めてきました。
AutoCloseableは簡単だし、ちょっと便利そうなので使ってみよう。
try ( Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery(sql); ) { while (rset.next()) { // ... } }
tryの最後にcatchもfinallyもないのはちょっと違和感あるけれども、いつもの if (null != conn) try { conn.close(); } catch (SQLException e) {} を書かなくて良いのはいいですね。しかも、自動クローズ中に発生した例外は、握りつぶしてしまうのではなく、ちゃんとSuppressedとして、元の例外に追加しておいてくれるみたいです。(Throwable#getSuppressed()で取得可能)
でもこれ、nullチェックとcloseだけやって欲しいのに、こうは書けないんですね。
Connection conn = null; Statement stmt = null; ResultSet rset = null; try ( // コンパイルエラー conn, stmt, rset ) { // ... }
つまり、何が困るかというと、tryブロックの開始と同時に生成するものしかAutoCloseableの恩恵を受けられないということです。
try ( Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql); ) { stmt.setInt(1, 1); stmt.setInt(2, 2); // ... // さて、こいつをどう解放する? ResultSet rset = stmt.executeQuery(); }
まあ、この場合はtryをネストすればOKですが。
try ( Connection conn = dataSource.getConnection(); java.sql.PreparedStatement stmt = conn.prepareStatement(sql); ) { stmt.setInt(1, 1); stmt.setInt(2, 2); // ... try (ResultSet rset = stmt.executeQuery()) { while (rset.next()) { // ... } } }
記述が冗長になるのが嫌でAutoCloseableを使いたいのに、ネストが深くなってしまうというのでは、なんだか半分損した気分になってしまいます。
もやもやした気持ちで、某スタックオーバーフローで情報を漁ってみました。
根本的な解決にはなりませんが、ResultSetはcloseしなくて良いそうです。
http://stackoverflow.com/questions/11454999/closing-resultset-in-java-7
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
ふ〜ん
まあ、これといった結論もなにもなく。
Javaカテゴリを追加しようかと思うほどの感動もなく。
おしまい