Попробуйте-поймать-наконец, а затем снова попробовать поймать - PullRequest
30 голосов
/ 26 августа 2009

Мне часто приходилось сталкиваться с такими ситуациями, как: -

try{ 
     ...
     stmts
     ...
} 
catch(Exception ex) {
     ... 
     stmts
     ... 
} finally {
     connection.close // throws an exception
}

который все еще нуждается в блоке try - catch внутри, наконец.

Как лучше всего преодолеть это?

Ответы [ 10 ]

25 голосов
/ 26 августа 2009

Напишите класс SQLUtils, который содержит 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()
)
{
  ...
}
12 голосов
/ 26 августа 2009

Как уже упоминалось, статическая утилита closeQuietly - это путь. Одна вещь, которую нужно добавить - если вы находитесь в мире java.io, а не java.sql, то для этой цели есть полезный интерфейс - java.io.Closeable

Все источники и приемники данных в java.io реализуют этот интерфейс - все потоки, каналы, устройства записи и чтения. Таким образом, вы можете создать одну утилиту для решения одной и той же проблемы «исключение при закрытии ()», не требуя много перегруженных версий.

, например

public class IoUtils {

  public static closeQuietly (Closeable closeable) {
    try {
      closeable.close();
    } catch (IOException logAndContinue) {
      ...
    }
  }

}
10 голосов
/ 26 августа 2009

Я обычно делал это так:

try {
    try {
        ..
        stmts
        ...
    }
    finally {
       connection.close():
    }
} catch (Exception ex) {
     ..
     stmts
     ..    
}

Обычно я использовал это, только когда не пользовался библиотекой, которая позаботилась об этом сантехнике для меня.

Как указывает Imagist , технически это не то же самое, что, наконец, будет выполняться до улова, но я думаю, что это решает проблему, которую вы пытались решить.

4 голосов
/ 26 августа 2009

Commons-io также имеет closeQuietly () для входного и выходного потоков. Я использую это все время. Это делает ваш код намного более читабельным.

1 голос
/ 10 декабря 2014

В 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) {
        }
    }
}
1 голос
/ 26 августа 2009

Не стесняйтесь, используйте еще одну попытку ... наконец поймайте внутрь.

0 голосов
/ 23 января 2014

Можем ли мы иметь блок try, за которым, наконец, bock и позже перехватить блок?

0 голосов
/ 22 марта 2013

В библиотеке Google Guava также есть удобный метод Closeables # closeQuately - его можно использовать для любого Closeable

0 голосов
/ 26 августа 2009

Как правило, вы не хотите ничего делать, кроме как записывать исключение, которое происходит при закрытии ресурса, поэтому он действительно должен идти своим собственным try / catch. Тем не менее, это общий код, который будет происходить часто, поэтому не повторяйте себя и не помещайте закрытие в статический метод (как предполагает Ник Холт), чтобы у вас не было двух элементов try / catch в одном и том же методе, облегчая чтение и следование коду.

0 голосов
/ 26 августа 2009

просто запомните .. наконец всегда выполняйте команду try или catch ..

...