Обработка исключений Java - стиль

Исторически я всегда писал свой код обработки исключений следующим образом:

    Cursor cursor = null;
    try {
        cursor = db.openCursor(null, null);
        // do stuff
    } finally {
        if (cursor != null) cursor.close();
    }

Но недавно, по соображениям удобочитаемости и лени, я начал это делать:

        Cursor cursor = db.openCursor(null, null);
        try {           
            // do stuff
        } finally {
            cursor.close();
        }

Неправильно ли мне назначить курсор (дескриптор jdbc, что угодно) из блока try-catch-finally?

Запрет JVM на самом деле взорвать назначение или между назначением и первой строкой того, что находится в блоке try. Я не уверен, что мой старый стиль выдавал какое-либо дополнительное значение, а второе, безусловно, более читаемо и кратким. В литературе обычно всегда идет с первым стилем.

EDIT - предположим, что я доволен любыми исключениями, вызванными openCursor при инициализации курсора, который не попадает в этот блок кода, моя единственная проблема для этого примера - это закрыть курсор, если он назначен и открыт. Также предположим, что я тестирую нули и т.д. И т.д. Yadda... yadda... (Я изменил пример, чтобы отразить это, это не было в центре моего вопроса, поэтому я не включил его в первую версию)

Ответ 1

Если все, что вы делаете в своем конце, закрывает курсор, тогда вторая форма верна. У вас никогда не будет курсора, если openCursor() завершится с ошибкой. Значение этой переменной даже не будет установлено.

Как и другие, оговорки заключаются в том, что если вы выполняете дополнительную инициализацию, требующую ее собственной очистки, тогда логически придется в конечном итоге {} и соответствующим образом изменить область. Хотя я бы поспорил о реструктуризации в этом случае.

В нижней строке: как написано, первая версия излишне сложна. Вторая версия верна.

Изменить: Включить мои другие комментарии для потомков...

Первый пример может показаться безобидным, поскольку все, что он делает, это добавить кучу ненужного кода. (Совершенно бесполезно, если это было непонятно.) Однако, в классическом стиле "больше кода означает больше потенциальных ошибок" есть скрытая информация.

Если по какой-либо причине код "//сделать что-то" непреднамеренно очищает переменную курсора, вы будете тихо просачивать курсоры, тогда как раньше вы, по крайней мере, получили исключение NullPointerException. Поскольку дополнительный код абсолютно ничего не полезен, дополнительный риск совершенно не нужен.

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

Ответ 2

Я всегда делаю свой второй способ, потому что он позволяет мне установить курсор как final. Нет причин, по которым я могу видеть назначение в предложении try, если вы на самом деле не пытаетесь поймать исключения из него.

РЕДАКТИРОВАТЬ: Просто отметьте, из дальнейшего обсуждения, которое продолжалось. Вот как я бы обработал вызов openCursor, бросая исключение:

try
{
    // ALLOCATE RESOURCE
    final Cursor cursor = db.openCursor(null, null);

    try
    {
        // USE RESOURCE
    }
    finally
    {
        // DISPOSE RESOURCE
        cursor.close();
    }
}
catch(OpenCursorException e)
{
    // Handle this appropriately.
}

Обратите внимание на четкое разделение распределения, использования и удаления. Единственный раз, когда это становится немного интересным, заключается в том, что если блок try использует одно и то же исключение, которое вы ловите для блока выделения try. (IOException был бы особенно хорошим примером этого, так как открытие и чтение могут бросать один.) В этом случае все будет по-прежнему чистым и корректным, но вы можете неправильно атрибут исключения для исключения инициализации вместо исключения использования, В этом случае вы захотите поймать исключение (исключения) во внутреннем блоке try и обработать их немедленно там.

Ответ 3

(Обновление: вопрос был исправлен на основе этого ответа, поэтому первая часть этого ответа больше не имеет смысла.)

Первый пример неверен. Он выкинет исключение NullPointerException, если db.openCursor завершится с ошибкой. Второй лучше.

Кстати, я часто вижу первый метод, выполненный следующим образом:

Cursor cursor = null;
try {
    cursor = db.openCursor(null, null);
    // do stuff
} finally {
    if (cursor != null) {
        cursor.close();
    }
}

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

Одна из причин, почему второй метод лучше, заключается в том, что ошибка в коде в разделе // do stuff может установить курсор в значение null, заставляя курсор не закрываться и создавая утечку. В целом я не вижу оснований для использования первого метода (даже если он исправлен с нулевой проверкой) и причины, чтобы избежать его использования. Придерживайтесь второго метода.

(Спасибо PSpeed ​​за полезные комментарии!)

Ответ 4

Нет, вы, наконец, все поняли.

Не назначать фиктивные значения (null, в данном случае), чтобы подавить предупреждения компилятора об использовании неинициализированных переменных. Вместо этого прислушайтесь к предупреждению и правильно инициализируйте свои переменные &mdash, как демонстрирует ваш второй, "ленивый" пример.

Ответ 5

В действительности нет ничего плохого:

Cursor cursor = db.openCursor(null, null);  
  try {  
     // do stuff  
   } finally {  
      try {  
        cursor.close();  
     } catch( SomeOther so ){}  
 }  

Ответ 6

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

Ответ 7

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

Ответ 8

У разных людей разные мнения. Но рекомендуется использовать первый вариант, потому что, если есть какие-либо проблемы с открытием курсора, исключение можно вызвать и обработать. Это один безопасный способ программирования.