在 try-with-resources 中进行空检查

null check in try-with-resources

我有以下代码:

try (Connection connection = getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement(someSql)) {//stuff}

如何检查这里的连接是否为空?

另外,我得到了一个 returns 像这样的 PreparedStatement 的方法:

private PreparedStatement getPreparedStatement(Connection connection)

  throws SQLException {

PreparedStatement preparedStatement = connection.prepareStatement(SQL);

preparedStatement.setString(1, "someString");

return preparedStatement;

}

这是在使用以下资源尝试的方法中调用的:

try (Connection connection = getConnection();
    PreparedStatement preparedStatement =
        getPreparedStatement(connection)) {//stuff}

现在我假设准备好的语句将自动关闭,因为它是在使用资源的尝试中启动的。但是 SonarCloud 说我应该在 getPreparedStatement 方法中尝试使用资源,或者在 finally 块中关闭该 PreparedStatement。这是 SonarCloud 的错误发现还是有更好的方法?

getConnection 应该抛出异常而不是 returning null。返回 null 不好 . SonarCloud seems to be wanting you to put a try-with-resource opening ingetPreparedStatement(must include thesetString`) 并关闭调用方法,当然你不能这样做。

最好的方法是Execute Around idiom。而不是 getPreparedStatement return 将 PreparedStatement 传递给要执行的 lambda(通常)。然后可以在 try-with-resource 语句中干净地关闭资源。

/*** NICE ***/
// Function instead of Consumer would allow the method to return a value.
private void prepared(
    Connection connection, Consumer<PreparedStatement> op
) throws SQLException {
    // Might want to add getConnection in here too, perhaps.
    try (
        PreparedStatement statement =
             connection.prepareStatement(SQL)
    ) { 
        statement.setString(1, "someString");
        op.accept(statement);
    }
}

用作:

    try (Connection connection = getConnection()) {
        prepared(connection, statement -> {
            // blah, blah, blah
        });
    }

替代方法是在 getPreparedStatement 中包含一个 try 语句,该语句仅在错误情况下关闭。

/*** HACKY ***/
private PreparedStatement prepared(
    Connection connection
) throws SQLException {
    boolean success = false;
    PreparedStatement statement =
        connection.prepareStatement(SQL);
    try { 
        statement.setString(1, "someString");
        success = true;
        return preparedStatement;
    } finally {
        if (!success) {
            statement.close();
        }
    }
}

如果您迫切希望 getConnection 到 return null(不要)并使用单个两次输入的 try-with-resource,则条件运算符有效。

try (
    Connection connection = getConnection();
    PreparedStatement statement =
        connection==null ? null : connection.prepareStatement(SQL)
) {

最简单的方法和 IMO 最可读的方法是使用 2 个 try-with-resources 块。即使是声纳也有一个内置的例外,就是不允许嵌套的 try-catch-blocks 正是这个用例...

try (Connection conn = getConnection()) {
    if (conn != null) {
        try (PreparedStatement stmt = ...) {
            // do stuff
        }
    }
}

如果 do stuff 很长,它可以而且应该重构为一个单独的方法(可能包括内部 try-with-resources)。