Try-catch-finally, а затем снова попытайтесь поймать
Я часто сталкивался с ситуациями вроде: -
try{
...
stmts
...
}
catch(Exception ex) {
...
stmts
...
} finally {
connection.close // throws an exception
}
который по-прежнему нуждается в блоке try-catch внутри.
Какова наилучшая практика для преодоления этого?
Ответы
Ответ 1
Напишите класс SQLUtils
который содержит static closeQuietly
методы static closeQuietly
которые перехватывают и регистрируют такие исключения, а затем используют их по мере необходимости.
Вы получите что-то вроде этого:
public class SQLUtils
{
private static Log log = LogFactory.getLog(SQLUtils.class);
public static void closeQuietly(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLExcetpion e)
{
log.error("An error occurred closing connection.", e);
}
}
public static void closeQuietly(Statement statement)
{
try
{
if (statement!= null)
{
statement.close();
}
}
catch (SQLExcetpion e)
{
log.error("An error occurred closing statement.", e);
}
}
public static void closeQuietly(ResultSet resultSet)
{
try
{
if (resultSet!= null)
{
resultSet.close();
}
}
catch (SQLExcetpion e)
{
log.error("An error occurred closing result set.", e);
}
}
}
И ваш код клиента будет выглядеть примерно так:
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try
{
connection = getConnection();
statement = connection.prepareStatement(...);
resultSet = statement.executeQuery();
...
}
finally
{
SQLUtils.closeQuietly(resultSet);
SQLUtils.closeQuietly(statment);
SQLUtils.closeQuietly(connection);
}
Обновление: начиная с Java 7, различные интерфейсы JDBC расширяют java.lang.AutoCloseable
и хотя приведенный выше код отвечает на первоначальный вопрос, если вы пишете код непосредственно для API JDBC, теперь его можно структурировать:
try (
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement(...);
ResultSet resultSet = statement.executeQuery()
)
{
...
}
Ответ 2
Как уже упоминалось, статическая утилита closeQuietly
- это путь. Добавим одно: если вы находитесь в мире java.io
, а не java.sql
, тогда для этого есть полезный интерфейс - java.io.Closeable
Все источники данных и приемники в java.io
реализуют этот интерфейс - все потоки, каналы, писатели и читатели. Таким образом, вы можете создать единую утилиту для решения одной и той же проблемы исключения при закрытии(), не требуя много перегруженных версий.
например.
public class IoUtils {
public static closeQuietly (Closeable closeable) {
try {
closeable.close();
} catch (IOException logAndContinue) {
...
}
}
}
Ответ 3
Я обычно делал это так:
try {
try {
..
stmts
...
}
finally {
connection.close():
}
} catch (Exception ex) {
..
stmts
..
}
Я обычно использовал это только тогда, когда я не использовал библиотеку, которая позаботилась об этом сантехнике для меня.
Как Imagist указывает, что это технически не то же самое, что, наконец, будет работать до улова, но я думаю, что он решает проблему, которую вы пытаетесь решать.
Ответ 4
Commons-io также имеет closeQuietly() для потоков ввода и вывода. Я использую его все время. Это делает ваш код более удобочитаемым.
Ответ 5
Не стесняйтесь использовать еще одну попытку... поймайте внутри наконец.
Ответ 6
В Java 10 вы можете написать:
public void java10() throws SQLException {
try (var connection = Connections.openConnection();
var callableStatement = connection.prepareCall("my_call");
var resultSet = callableStatement.executeQuery()) {
while (resultSet.next()) {
var value = resultSet.getString(1);
System.out.println(value);
}
}
}
В Java 7, 8 и 9 вы можете написать:
public void java7() throws SQLException {
try (Connection connection = Connections.openConnection();
CallableStatement callableStatement = connection.prepareCall("my_call");
ResultSet resultSet = callableStatement.executeQuery()) {
while (resultSet.next()) {
String value = resultSet.getString(1);
System.out.println(value);
}
}
}
В Java 6 вам нужно написать все эти строки:
public void java6() throws SQLException {
Connection connection = Connections.openConnection();
try {
CallableStatement callableStatement = connection.prepareCall("my_call");
try {
ResultSet resultSet = callableStatement.executeQuery();
try {
while (resultSet.next()) {
String value = resultSet.getString(1);
System.out.println(value);
}
} finally {
try {
resultSet.close();
} catch (Exception ignored) {
}
}
} finally {
try {
callableStatement.close();
} catch (Exception ignored) {
}
}
} finally {
try {
connection.close();
} catch (Exception ignored) {
}
}
}
Ответ 7
Как правило, вы не хотите делать ничего больше, чем регистрировать исключение, которое происходит при закрытии ресурса, поэтому оно должно действительно идти по собственному try/catch. Однако это общий код, который будет происходить часто, поэтому Do not Repeat Yourself и поместите закрытие в статический метод (как предполагает Ник Холт) таким образом, у вас не будет двух элементов try/catch в том же методе, делая код более легким для чтения и наблюдения.
Ответ 8
В Google Guava есть удобный метод Closeables # closeQuitely - он может использоваться для любого Closeable
Ответ 9
Можем ли мы попробовать блок, за которым следует, наконец, bock и блок catch позже?
Ответ 10
просто запомните.. наконец-то всегда выполняйте выполнение либо с помощью try, либо catch.