Java: как объявить окончательную переменную, которая инициализируется внутри блока try-catch?

У меня есть переменная, которая не должна изменять ее значение после ее инициализации, поэтому я хочу определить ее как конечную переменную.

проблема в том, что переменная должна быть инициализирована внутри блока try, поэтому я получаю следующие проблемы:

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

Connection conn = null;
try {
    conn = getConn(prefix);
    [...do some stuff with conn...]
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}

Если я объявляю переменную как final, не инициализируя ее значением null, я получаю "Локальная переменная conn, возможно, не была инициализирована" на блоке finally. С другой стороны, если я объявляю его окончательным и инициализирую его значением null, я получаю сообщение об ошибке "Конечная локальная переменная conn не может быть назначена" в блоке try.

EDIT: после ответа lxx я пришел с этой версией

try {
    final Connection conn = conn = getConn(prefix);
    try {
        return selectAll(conn, sql, params);
    } catch (Exception e) {
        throw new DbHelperException("error executing query", e);
    } finally {
        closeConnection(conn);  
    }
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
}

Итак, это должен быть способ сделать это?

-

Извлеченный урок:

Я думаю, что правильный ответ на вопрос - это тот, который дал lxx, но в этом случае я предполагаю, что минусы объявления переменных конечных перегрузок выгодны...

-

EDIT: найдено два вопроса о переполнении стека о том, когда использовать final

Когда следует использовать final для параметров метода и локальных переменных?

Использование "final" модификатор, когда это применимо в java.

Ответ 1

Вы можете справиться с Исключениями более точно. Если вы получите сообщение об исключении, вам не нужно закрывать его в блоке finally, я думаю. Если после этого вы получаете исключение, в блоке try и обрабатываете исключение в новом вложенном блоке try-catch, вам не нужно определять переменную снаружи. Что-то вроде:

    try {
        final Connection conn = getConn(prefix);
        try {
            //code using conn
        } catch (Exception e) {

        } finally {
            closeConnection(conn);
        }
    } catch (DbHelperException e) {
        throw new DbHelperException("error opening connection", e);
    }

Ответ 2

Как насчет этого?

Connection temp = null;
try {
    temp = getConn(prefix);
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}
final Connection conn = temp;

Ответ 3

Почему вы хотите, чтобы он был окончательным? Если вы хотите передать его анонимному внутреннему классу, вы можете сделать:

Connection conn = null;
try {
    conn = getConn(prefix);
    final Connection finalConn = conn;
    // pass it to inner class here
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}

Единственная проблема (и довольно большая) с этим решением заключается в том, что вы закрываете свое соединение, как только покидаете этот блок. Поэтому, если вы не сразу объявите и не назовете ваш внутренний класс anon, этот шаблон не будет работать.

В любом случае, я бы, вероятно, перефразировал все это, если бы я был вами, сделав вместо этого prefix final и делегируя обработку соединения внутреннему классу anon.

Ответ 4

Можете ли вы попытаться присвоить его как в блоках catch, так и finally? Например:

Connection connTemp = null;
final Connection conn;
try {
    connTemp = getConn(prefix);
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}
conn = connTemp;