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カテゴリを追加しようかと思うほどの感動もなく。

おしまい