проверка нуля в try-with-resources - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть следующий код:

try (Connection connection = getConnection();

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

Как проверить, что здесь соединение не равно нулю?

Также у меня есть метод, который возвращает 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 говорит, что я должен использовать try с ресурсами в методе getPreparedStatement или закрыть этот PreparedStatement в блоке finally. Это неправильный вывод SonarCloud или есть лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 28 февраля 2020

getConnection должен выдать исключение вместо возврата null. Возвращать null нехорошо . SonarCloud seems to be wanting you to put a try-with-resource opening in getPreparedStatement (must include the setString`) и закрывать в вызывающем методе, что, конечно, вы не можете сделать так.

Наилучший подход - это Выполнить Вокруг идиома . Вместо getPreparedStatement возвращает PreparedStatement проход в лямбда-выражении (обычно) для выполнения. Затем ресурс может быть чисто закрыт в операторе 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
        });
    }

Хакерская альтернатива - включить оператор try в getPreparedStatement это только закрыто в условиях ошибки.

/*** 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 возвратил null (не) и использовал одну попытку записи с ресурсом из двух записей, тогда условный оператор работает.

try (
    Connection connection = getConnection();
    PreparedStatement statement =
        connection==null ? null : connection.prepareStatement(SQL)
) {
0 голосов
/ 28 февраля 2020

Самый простой подход и IMO самый читаемый - использовать 2 блока try-with-resources. Даже у сонара есть встроенное исключение из запрета вложенных блоков try-catch для именно этого варианта использования ...

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

Если do stuff длинен, он может и должен быть преобразован в отдельный метод (возможно, включая внутреннюю попытку с ресурсами).

...