Обработка исключений Java - Стиль - PullRequest
10 голосов
/ 15 декабря 2009

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

    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. Я не уверен, давал ли мой старый стиль какое-либо дополнительное значение, а второй, безусловно, более читабелен и краткий. Литература , как правило, всегда соответствует первому стилю.

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

Ответы [ 8 ]

13 голосов
/ 15 декабря 2009

Я всегда делаю мой второй способ, потому что он позволяет мне установить курсор как 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 и немедленно обработать их там.

11 голосов
/ 15 декабря 2009

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

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

Между прочим, я часто вижу первый метод, сделанный так:

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

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

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

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

6 голосов
/ 15 декабря 2009

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

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

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

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

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

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

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

6 голосов
/ 15 декабря 2009

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

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

1 голос
/ 15 декабря 2009

В этом нет ничего плохого:

Cursor cursor = db.openCursor(null, null);  
  try {  
     // do stuff  
   } finally {  
      try {  
        cursor.close();  
     } catch( SomeOther so ){}  
 }  
0 голосов
/ 29 апреля 2011

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

0 голосов
/ 15 декабря 2009

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

0 голосов
/ 15 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...