2

The Java tutorial state that you can do the following with try-with-resources:

try (Statement stmt = con.createStatement()) {
    ResultSet rs = stmt.executeQuery(query);
    ...
} catch (SQLException e) {
    ...
}

In this tutorial the ResultSet is never closed, thus I want to include the ResultSet , as it also implements the AutoCloseable interface, like so:

try (Statement stmt = con.createStatement(); 
     ResultSet rs = stmt.executeQuery(query)) {
    ...
} catch (SQLException e) {
    ...
}

This works fine, but when it comes to PreparedStatements I want to be able to set some values on the before executing the query:

String name = "Ian";
try (PreparedStatement pstmt = getPreparedStatement(con, stmt); 
     pstmt.setString(1, name);
     ResultSet rs = pstmt.executeQuery(query)) {
    ...
} catch (SQLException e) {
    ...
}

This causes a range of compilation errors, because (I am assuming) only variable assignment is allowed.

Is there anyway to do this neatly in the same try-with-resources block?

I have already thought of:

  1. Nested try-with-resources (which is what I am trying to avoid). I realise there is nothing 'wrong' with doing so, I merely want to do this for the sake of readability.

Consider the following to cases:

try (MyObject1 o1 = new MyObject1()) {
    o1.setSomeValue();
    try (MyObject2 o2 = new MyObject2(o1)) {
        o2.setSomeValue();
        try (MyObject3 o3 = new MyObeject3(o2) {
            o3.setSomeValue();
            // do work here
        }
    }
} catch (Exception e) {
    ...
}

vs

try (MyObject1 o1 = new MyObject1();
     o1.setSomeValue();
     MyObject3 o2 = new MyObeject2(o1);
     o2.setSomeValue();
     MyObject3 o3 = new MyObeject3(o2);
     o3.setSomeValue()) {

    // do work here
} catch (Exception e) {
    ...
}
  1. Having setString() method return the object and include it in assignment
  2. Creating some sort of helper method that creates the connection and sets parameters accordingly.

Something like:

public PreparedStatement createPreparedStatement(Connection con, String stmt, Object ... params) {

}
Ian2thedv
  • 2,691
  • 2
  • 26
  • 47
  • You could use a nested `try` without a `catch`. This would close the `ResultSet` and any occuring exception would be handled by the outer catch block. – André Stannek Jan 15 '16 at 08:54

3 Answers3

3

I guess you meant Connection.prepareStatement().

There is no need to close the ResultSet explicitely, since API-Doc of Statement.close guarantees to close its ResultSet. So it's fine to write

try (PreparedStatement stmt = con.prepareStatement(query)) {
    stmt.setString(1, name);
    ResultSet rs = stmt.executeQuery(query);
    ...
}
catch (SQLException e) {
    ...
}
Frank Neblung
  • 3,047
  • 17
  • 34
  • Ah! This does actually solve the problem I am facing (and that of my example) but this is not sufficient to answer the entire question. – Ian2thedv Jan 15 '16 at 09:25
1

If you want to set some value between constructing the Statement and the ResultSet you will need nested try-with-resources blocks. Why are you trying to avoid that? There's nothing wrong with doing so.

You could define some unwieldy number of helper methods, but except for a few very high-usage cases this will be much more trouble than it's worth.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • I understand that there is nothing wrong with it. I have update my answer to explain why I want to avoid nested blocks. – Ian2thedv Jan 15 '16 at 09:16
0

You can like this:

try (
     Connection con = em.unwrap(Connection.class);
     PreparedStatement ps = TryJumper.jump(con.prepareStatement("select * from x where a = ?"), pss -> {
         pss.setInt(1, 123);
     });
     ResultSet rs = ps.getResultSet();
) {
    //core codes
} catch (Exception e) {
    e.printStackTrace();
}

Necessary class

public class TryJumper {

    public static <M> M jump(M m, MUser<M> mUser) throws Exception {
        mUser.consume(m);
        return m;
    }

    interface MUser<M> extends AutoCloseable {
        void consume(M m) throws Exception;

        @Override
        default void close() throws Exception {
        }
    }

}

How is it work:

In try catch resources everything should return an Object which implement from AutoClosable interface. This class simply returning same object which you pass after your consume method work (in lambda)

utrucceh
  • 1,076
  • 6
  • 11