【问题标题】:Call method on object in try-with-resources block在 try-with-resources 块中调用对象的方法
【发布时间】:2016-04-20 19:45:05
【问题描述】:

Java tutorial 状态,您可以使用try-with-resources 执行以下操作:

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

在本教程中 ResultSet 永远不会关闭,因此我想包含 ResultSet ,因为它还实现了 AutoCloseable 接口,如下所示:

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

这很好用,但是当涉及到PreparedStatements 时,我希望能够在 执行查询之前设置一些值:

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

这会导致一系列编译错误,因为(我假设)只允许变量赋值。

有没有办法在同一个try-with-resources 块中巧妙地做到这一点?

我已经想到了:

  1. 嵌套的 try-with-resources(这是我试图避免的)。我意识到这样做并没有什么“错误”,我只是为了可读性而这样做。

考虑以下情况:

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) {
    ...
}

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. setString() 方法返回对象并将其包含在赋值中
  2. 创建某种帮助方法来创建连接并相应地设置参数。

类似:

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

}

【问题讨论】:

  • 您可以使用嵌套的try 而不使用catch。这将关闭ResultSet,并且任何发生的异常都将由外部 catch 块处理。

标签: java prepared-statement try-with-resources autocloseable


【解决方案1】:

我猜你的意思是Connection.prepareStatement()

没有必要明确关闭 ResultSet,因为Statement.close 的 API-Doc 保证关闭其 ResultSet。这样写就好了

try (PreparedStatement stmt = con.prepareStatement(query)) {
    stmt.setString(1, name);
    ResultSet rs = stmt.executeQuery(query);
    ...
}
catch (SQLException e) {
    ...
}

【讨论】:

  • 啊!这确实解决了我面临的问题(以及我的示例),但这不足以回答整个问题。
【解决方案2】:

如果您想在构造 StatementResultSet 之间设置一些值,您将需要嵌套的 try-with-resources 块。你为什么要避免这种情况?这样做没有错。

你可以定义一些笨重的辅助方法,但是除了一些非常高使用率的情况之外,这将比它的价值更麻烦。

【讨论】:

  • 我明白这并没有什么问题。我已经更新了我的答案来解释我为什么要避免嵌套块。
【解决方案3】:

你可以这样:

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();
}

必要的类

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 {
        }
    }

}

它是如何工作的:

在 try catch 资源中,一切都应该返回一个 Object,它从 AutoClosable 接口实现。此类仅返回您在使用方法工作后传递的相同对象(在 lambda 中)

【讨论】:

    猜你喜欢
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    相关资源
    最近更新 更多