Я не буду использовать оператор try-catch в блоке finally. (Ява)

Вот некоторый код Java.

public class SomeClass {
private Connection connection;

public SomeClass(Connection c) {
    connection = c;
}
public void someWork(){
    Connection c;
    try {
        // do something
    } catch (Exception e) {
        // some exception code
    } finally {
        if (conn != null){
            try {c.close();} catch (Exception e) {}
        }
    }
}

}

но мне не нравится код

if (conn != null){
        try {c.close();} catch (Exception e) {}
    }

так что я думаю код

...catch (Exception e) {
        // some exception code
    } finally {
        c = null;
    }

но я вижу «Объект потока не собранный мусор».

Я не буду использовать оператор try-catch в блоке finally. Пожалуйста, дайте мне другой способ.


person user2503993    schedule 20.06.2013    source источник
comment
Почему бы и нет? Серьезно, я не вижу причин для произвольного запрета языковой конструкции, вложенной в другую.   -  person michaelb958--GoFundMonica    schedule 20.06.2013
comment
Что еще более важно, почему вы игнорируете исключение? Каждый раз, когда я вижу блок try catch, который просто проглатывает исключение, мне хочется плакать. Это просто усложняет чью-то жизнь при отладке позже.   -  person Paddy    schedule 20.06.2013


Ответы (7)


Просто создайте статический служебный метод:

private static void closeQuietly(final Connection conn)
{
    if (conn == null)
        return;
    try {
        conn.close();
    } catch (WhateverException ignored) {
    }
}

потом

conn = whatever(); // create it there, not in the try block
try {
    // work
} catch (WhateverException e) {
    // whatever
} finally {
    closeQuietly(conn);
}

Но со временем вы все равно все равно будете использовать try/catch в блоке finally.

Обратите внимание, что поймать Exception — это плохая идея. Вместо этого перехватывайте исключения, специально вызванные conn.close(). Поймать Exception означает, что вы также поймаете все RuntimeException; и это Плохая Вещь (тм).

Если вы используете Guava, вы также можете использовать Closeables.closeQuietly(), который делает почти то же самое, что и приведенный выше код. Вы также можете ознакомиться с Closer< /a>, что очень интересно.

Наконец (каламбур): если вы используете Java 7, вместо этого используйте оператор try-with-resources (см. AutoCloseable):

try (
    conn = whatever();
) {
    // ...
}
person fge    schedule 20.06.2013
comment
Спасибо за информацию. я должен написать о моем окружении. я использую jdk 6. но я действительно не нахожу причин, по которым ловить исключения для каждого случая. я обычно использую Exception e и e.printStackTrace(), тогда это работает так java.sql.SQLException: ORA-00936: missing expression at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:138) вы действительно думаете, что это плохой способ? Я думаю, что поймал ошибку, что это такое и где это. - person user2503993; 21.06.2013
comment
Я говорю, что если вы поймаете Exception, вы также поймаете исключения, которые не имеют ничего общего с вашим рабочим процессом. - person fge; 21.06.2013

Другим обходным решением для этого может быть полное удаление улова внутри метода:

public void someWork() throws SQLException{
    Connection c;
    try {
        // do something
    } finally {
        if (conn != null){
            c.close();
        }
    }
}

Затем вы выполняете проверку ошибок вне метода в основном методе, где вы вызвали метод someWork, или вы переносите его в другой метод, где вы вызываете someWork():

 public void callSomeWork(){
    try{
     someWork();
    }catch(SQLException ex){
    //handle SQL error here
    }
 }

Таким образом, ошибка, возникающая при попытке или, наконец, будет объявлена ​​​​в одном SQLException.

person mel3kings    schedule 20.06.2013

Вам может не понравиться этот код, но в данной ситуации он необходим. (Хотя вы можете обернуть код в такой метод, как метод closeQuietly @fge.)

Но есть более фундаментальная проблема. Изменение someWork для закрытия соединения в блоке finally недостаточно для предотвращения утечки... в этой ситуации!!

Почему?

Учти это:

SomeClass sc = new SomeClass(createConnection());
// do some stuff
sc.someWork();

Вопрос 1. Что произойдет, если в коде «сделать что-нибудь» возникнет исключение?

Q2: Что произойдет, если возникнет исключение при создании/конструкции SomeClass? (Примечание: это возможно даже с самыми простыми конструкторами. Например, OOME может быть вызван операцией new...)

Ответ: Объект Connection утек... в обеих базах!


Исправление состоит в том, чтобы выделить ресурс (например, объект Connection) внутри или непосредственно перед try/catch/finally; например

Connection c = createConnection();
try {
    // do something
} catch (SomeException e) {
    // some exception code
} finally {
    if (c != null){
        try {c.close();} catch (SomeException e) {}
    }
}

В Java 7 вы также можете написать это так:

try (Connection c = createConnection()) {
    // do something
} catch (SomeException e) {
    // some exception code
}

при условии, что Connection реализует интерфейс AutoCloseable. Версия Java 7 — это «синтаксический сахар» для более сложной реализации, которая заботится о проверке null, вызове close() и разумной обработке любых результирующих исключений. (JLS дает подробную информацию о том, что на самом деле делает «попробовать с ресурсом».)


Для записи:

person Stephen C    schedule 20.06.2013
comment
@ user2503993 - К сожалению. Но если вы собираетесь использовать устаревшую версию языка, вам придется смириться с ее ограничениями. Учись нравиться. - person Stephen C; 21.06.2013
comment
@ user2503993 - Также обратите внимание (И СКАЖИТЕ ВАШЕМУ БОССУ / КЛИЕНТАМ), что Java 6 устарела. Больше никаких обновлений безопасности... если только он/они не заключат контракт на поддержку Oracle Java. java.com/en/download/faq/java_6.xml - person Stephen C; 21.06.2013

Возможно, вы выходите из зомби-соединения, если оно не закрыто и установлено в NULL.

person Juned Ahsan    schedule 20.06.2013

Начиная с Java 7, это должно быть так

try (Connection conn = DriverManager.getConnection(props)) {
    ...
}

до Явы 7

Connection conn = DriverManager.getConnection();
try {
  ...
} finally {
    conn.close();
}
person Evgeniy Dorofeev    schedule 20.06.2013

Если вы аннулируете и не закрываете, убедитесь, что все методы всегда получают новое открытое соединение.

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

person Suresh Atta    schedule 20.06.2013

позвольте кому-нибудь другому сделать попытку-поймать и использовать IOUtils Apache Commons

Один из closeQuietly()-методов (например, этот) должен быть именно тем, что вам нужно:

Эквивалентно InputStream.close(), за исключением того, что любые исключения будут игнорироваться. Обычно это используется в блоках finally.

person Marco Forberg    schedule 20.06.2013