Почему пустые блоки блокировки имеют плохую идею?

Я только что рассмотрел вопрос о try-catch, который люди (в том числе Джон Скит) говорят, что пустые блоки блокировки - действительно плохая идея? Почему это? Нет ли ситуации, когда пустой улов не является неправильным дизайнерским решением?

Я имею в виду, например, иногда вы хотите получить некоторую дополнительную информацию где-нибудь (webservice, database), и вам действительно все равно, получите ли вы эту информацию или нет. Поэтому вы пытаетесь его получить, и если что-нибудь случится, это нормально, я просто добавлю "catch (исключение проигнорировано) {}" и что все

Ответ 1

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

Это программный эквивалент нанесения черной ленты на сигнальную лампу двигателя.

Я считаю, что то, как вы справляетесь с исключениями, зависит от того, на каком слое программного обеспечения вы работаете: Исключения в Rainforest.

Ответ 2

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

Сказать, что это всегда плохо, неверно... это правда очень мало. Могут быть обстоятельства, при которых вам все равно, что произошла ошибка, или что наличие ошибки каким-то образом указывает на то, что вы ничего не можете с этим поделать (например, при записи предыдущей ошибки в файл текстового журнала и вы получаете IOException, что означает, что вы все равно не могли выписать новую ошибку).

Ответ 3

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

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

Например, рассмотрим некоторую библиотеку http-сервера, мне все равно, если сервер выдает исключение, потому что клиент отключился и index.html не удалось отправить.

Ответ 4

Есть редкие случаи, когда это может быть оправдано. В Python вы часто видите такую ​​конструкцию:

try:
    result = foo()
except ValueError:
    result = None

Так что может быть ОК (в зависимости от вашего приложения):

result = bar()
if result == None:
    try:
        result = foo()
    except ValueError:
        pass # Python pass is equivalent to { } in curly-brace languages
 # Now result == None if bar() returned None *and* foo() failed

В недавнем .NET-проекте мне пришлось написать код для перечисления DLL-модулей плагинов, чтобы найти классы, реализующие определенный интерфейс. Соответствующий бит кода (в VB.NET, извините):

    For Each dllFile As String In dllFiles
        Try
            ' Try to load the DLL as a .NET Assembly
            Dim dll As Assembly = Assembly.LoadFile(dllFile)
            ' Loop through the classes in the DLL
            For Each cls As Type In dll.GetExportedTypes()
                ' Does this class implement the interface?
                If interfaceType.IsAssignableFrom(cls) Then

                    ' ... more code here ...

                End If
            Next
        Catch ex As Exception
            ' Unable to load the Assembly or enumerate types -- just ignore
        End Try
    Next

Хотя даже в этом случае я бы признал, что регистрация ошибки где-то, вероятно, будет улучшением.

Ответ 5

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

В соответствующей заметке большинство людей не знают, что для блока try {} может следовать либо catch {}, либо finally {}, требуется только один.

Ответ 6

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

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

Ответ 7

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

Но даже в этом случае сообщение отладки может быть в порядке.

Ответ 8

Per Josh Bloch - Пункт 65: Не игнорируйте Исключения Эффективная Java:

  • Пустой блок catch поражает цель исключений
  • По крайней мере, блок catch должен содержать комментарий, объясняющий, почему уместно игнорировать исключение.

Ответ 9

Пустой блок catch по существу говорит: "Я не хочу знать, какие ошибки выбрасываются, я просто проигнорирую их".

Он похож на VB6 On Error Resume Next, за исключением того, что что-либо в блоке try после того, как выбрано исключение, будет пропущено.

Это не помогает, когда что-то прерывается.

Ответ 10

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

Ответ 11

Я думаю, что полностью пустой блок catch - плохая идея, потому что нет никакого способа сделать вывод о том, что игнорирование исключения было предполагаемым поведением кода. Не обязательно плохо проглатывать исключение и возвращать ложные или нулевые значения или некоторые другие значения в некоторых случаях. В .net framework есть много методов "try", которые ведут себя таким образом. Как правило, если вы проглотите исключение, добавьте комментарий и оператор журнала, если приложение поддерживает ведение журнала.

Ответ 12

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

Ответ 13

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

Ответ 14

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

try
{
    // Do some processing.
}
catch (FileNotFound fnf)
{
    HandleFileNotFound(fnf);
}
catch (Exception e)
{
    if (!IsGenericButExpected(e))
        throw;
}

public bool IsGenericButExpected(Exception exception)
{
    var expected = false;
    if (exception.Message == "some expected message")
    {
        // Handle gracefully ... ie. log or something.
        expected = true;
    }

    return expected;
}

Ответ 15

Я нахожу наиболее раздражающим с пустым оператором catch, когда это сделал какой-то другой программист. Я имею в виду, когда вам нужно отлаживать код от кого-то другого, любые пустые операторы catch делают такое мероприятие более сложным, чем это необходимо. Операторы catch IMHO должны всегда показывать какое-то сообщение об ошибке - даже если ошибка не обрабатывается, она должна, по крайней мере, обнаружить ее (только в режиме отладки)

Ответ 16

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

Я могу только подумать о нескольких случаях, когда пустой блок catch имеет какую-то значимую цель. Если какое-либо конкретное исключение, которое вы ловите, "обрабатывается", просто повторив действие, в блоке catch не нужно ничего делать. Тем не менее, было бы неплохо зарегистрировать тот факт, что произошло исключение.

Другой пример: CLR 2.0 изменил способ обработки необработанных исключений в потоке финализатора. До 2.0 процесс позволил выжить в этом сценарии. В текущем CLR процесс завершается в случае необработанного исключения в потоке финализатора.

Имейте в виду, что вам нужно только реализовать финализатор, если вам действительно нужен один, и даже тогда вы должны сделать немного по возможности в финализаторе. Но если какая-либо работа, которую должен выполнить ваш финализатор, может вызвать исключение, вам нужно выбрать между меньшим количеством двух зол. Вы хотите закрыть приложение из-за необработанного исключения? Или вы хотите перейти в более или менее состоянии undefined? По крайней мере теоретически последнее может быть меньшим из двух зол в некоторых случаях. В этом случае пустой блок catch предотвратит завершение процесса.

Ответ 17

Я имею в виду, например, иногда вы хотите получить некоторую дополнительную информацию где-нибудь (webservice, database), и вам действительно все равно, получите ли вы эту информацию или нет. Поэтому вы пытаетесь его получить, и если что-нибудь случится, это нормально, я просто добавлю "catch (Exception ignored) {}" и что все

Итак, идем с вашим примером, это плохая идея в этом случае, потому что вы ловите и игнорируете все исключения. Если вы ловили только EInfoFromIrrelevantSourceNotAvailable и игнорировали его, это было бы хорошо, но вы не. Вы также игнорируете ENetworkIsDown, что может быть или не быть важным. Вы игнорируете ENetworkCardHasMelted и EFPUHasDecidedThatOnePlusOneIsSeventeen, которые почти наверняка важны.

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

Ответ 18

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

Ответ 19

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

  • регистрация исключений; в зависимости от контекста вам может потребоваться необработанное исключение или отправленное сообщение.

  • циклические технические ситуации, такие как обработка рендеринга или звука или обратный вызов списка, где само поведение будет демонстрировать проблему, бросание исключения будет просто мешать, и регистрация исключения будет, вероятно, просто результатом 1000 Сообщение "не удалось выполнить XXX".

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

для большинства приложений winforms, я обнаружил, что для каждого пользовательского ввода достаточно иметь один оператор try. Я использую следующие методы: (AlertBox - это просто быстрая оболочка MessageBox.Show)

  public static bool TryAction(Action pAction)
  {
     try { pAction(); return true; }
     catch (Exception exception)
     {
        LogException(exception);
        return false;
     }
  }

  public static bool TryActionQuietly(Action pAction)
  {
     try { pAction(); return true; }
     catch(Exception exception)
     {
        LogExceptionQuietly(exception);
        return false;
     }
  }

  public static void LogException(Exception pException)
  {
     try
     {
        AlertBox(pException, true);
        LogExceptionQuietly(pException);
     }
     catch { }
  }

  public static void LogExceptionQuietly(Exception pException)
  {
     try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
  }

Затем каждый обработчик событий может сделать что-то вроде:

  private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
  {
     EditorDefines.TryAction(Dispose);
  }

или

  private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
  {
     EditorDefines.TryActionQuietly(() => Render(pEventArgs));
  }

Теоретически у вас может быть TryActionSilently, что может быть лучше для визуализации вызовов, чтобы исключение не генерировало бесконечное количество сообщений.

Ответ 20

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

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }