Почему пустые блоки catch плохая идея? [закрытый]
Я только что видел вопрос о try-catch, какие люди (включая Джона Скита) говорят, что пустые блоки catch-это действительно плохая идея? Почему это? Нет ли ситуации, когда пустой улов не является неправильным проектным решением?
Я имею в виду, например, иногда вы хотите получить дополнительную информацию откуда-то (веб-сервис, база данных), и вам действительно все равно, получите ли вы эту информацию или нет. Поэтому вы пытаетесь получить его, и если что-то произойдет, это нормально, я просто добавлю " catch (исключение игнорируется) {} " и это все
20 ответов:
обычно пустой try-catch-это плохая идея, потому что вы молча проглатываете условие ошибки, а затем продолжаете выполнение. Иногда это может быть правильным решением, но часто это признак того, что разработчик увидел исключение, не знал, что с этим делать, и поэтому использовал пустой улов, чтобы замолчать проблему.
это программный эквивалент надевания черной ленты на сигнальную лампу двигателя.
Я считаю, что как вы справляетесь с исключениями зависит от на каком уровне программного обеспечения вы работаете:исключения в тропическом лесу.
это плохая идея В общем потому что это действительно редкое состояние, когда отказ (исключительное условие, более обобщенно) должным образом встречен без ответа вообще. Кроме того, пусто
catchблоки-это общий инструмент, используемый людьми, которые используют механизм исключений для проверки ошибок, которые они должны делать упреждающе.сказать, что это всегда плохо не соответствует действительности...это касается очень немногого. Там могут быть обстоятельства, когда либо вы не волнует, что произошла ошибка или что наличие ошибки каким-то образом указывает на то, что вы ничего не можете с этим поделать (например, при записи предыдущей ошибки в текстовый файл журнала и вы получаете
IOException, что означает, что вы не могли написать новую ошибку в любом случае).
Я бы не стал растягивать вещи настолько, чтобы сказать, что тот, кто использует пустые блоки catch, является плохим программистом и не знает, что он делает...
при необходимости я использую пустые блоки catch. Иногда программист библиотеки, которую я потребляю, не знает, что он делает, и бросает исключения даже в ситуациях, когда это никому не нужно.
например, рассмотрим некоторую библиотеку http-сервера, Мне все равно, если сервер выдает исключение, потому что клиент отключен и
index.htmlне может быть отправлено.
бывают редкие случаи, когда это может быть оправдано. В 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 плагинов, чтобы найти классы, реализующие определенный интерфейс. Соответствующий бит кода (in 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хотя даже в этом случае я бы признал, что регистрация сбоя где-то наверное, было бы лучше.
пустые блоки catch обычно вставляются, потому что кодер действительно не знает, что они делают. В моей организации пустой блок catch должен содержать комментарий о том, почему ничего не делать с исключением-это хорошая идея.
в соответствующей заметке большинство людей не знают, что за блоком try{} может следовать либо catch {}, либо finally {}, требуется только один.
исключения должны быть брошены только в том случае, если действительно есть исключение - что-то происходит за пределами нормы. Пустой блок catch в основном говорит:"что-то плохое происходит, но мне просто все равно". Это плохая идея.
Если вы не хотите обрабатывать исключение, пусть оно распространяется вверх, пока не достигнет некоторого кода, который может его обрабатывать. Если ничто не может обработать исключение, оно должно снять приложение.
Я думаю, что это нормально, если вы ловите особенности тип исключения, о котором вы знаете, что он будет поднят только для одного особенности причина, и вы ожидаете, что исключение и действительно не нужно ничего с этим делать.
но даже в этом случае, сообщение отладки может быть в порядке.
на Джош Блох -пункт 65: не игнорируйте исключения на Эффективная Java:
- пустой блок catch побеждает цель исключений
- по крайней мере, блок catch должен содержать комментарий, объясняющий, почему уместно игнорировать исключение.
пустой блок catch по существу говорит: "Я не хочу знать, какие ошибки выбрасываются, я просто собираюсь игнорировать их."
это похоже на VB6 в
On Error Resume Next, за исключением того, что все, что в блоке try после исключения будет пропущено., который не помогает, когда что-то ломается.
Это идет рука об руку с "не используйте исключения для управления потоком программы.", и, " используйте только исключения для исключительных обстоятельств."Если это сделано, то исключения должны происходить только тогда, когда есть проблема. И если есть проблема, вы не хотите потерпеть неудачу молча. В редких аномалиях, где нет необходимости обрабатывать проблему, вы должны по крайней мере регистрировать исключение, на случай, если аномалия больше не станет аномалией. Единственное, что хуже не будет не молча.
Я думаю, что полностью пустой блок catch-это плохая идея, потому что нет способа сделать вывод, что игнорирование исключения было предполагаемым поведением кода. Не обязательно плохо проглотить исключение и вернуть false или null или какое-то другое значение в некоторых случаях. Платформа .net framework имеет много методов "try", которые ведут себя таким образом. Как правило, если вы проглатываете исключение, добавьте комментарий и инструкцию журнала, если приложение поддерживает ведение журнала.
потому что если исключение и брошенный вы никогда не увидите его-сбой молча является худшим возможным вариантом-вы получите ошибочное поведение и не знаете, где это происходит. По крайней мере, поместите туда сообщение журнала! Даже если это то, что "никогда не может произойти"!
пустые блоки catch-это признак того, что программист не знает, что делать с исключением. Они подавляют исключение, возможно, пузырящееся и правильно обрабатываемое другим блоком try. Всегда старайтесь делать что-то за исключением того, что вы ловите.
Я считаю, что больше всего раздражает пустые операторы catch, когда это сделал какой-то другой программист. Я имею в виду, когда вам нужно отлаживать код от кого-то другого, любые пустые операторы catch делают такое предприятие более сложным, чем это должно быть. Операторы IMHO catch всегда должны показывать какое - то сообщение об ошибке-даже если ошибка не обрабатывается, она должна по крайней мере обнаружить ее (alt. только в режиме отладки)
Это, вероятно, никогда не правильно, потому что вы молча проходите каждый возможны исключения. Если есть конкретное исключение, которое вы ожидаете, то вы должны проверить его, перестроить, если это не ваше исключение.
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; }
Как правило, вы должны ловить только исключения, которые вы действительно можете обрабатывать. Это означает быть как можно более конкретным при перехвате исключений. Перехват всех исключений редко бывает хорошей идеей, а игнорирование всех исключений почти всегда очень плохая идея.
Я могу только думать о нескольких случаях, когда пустой блок catch, имеет некоторые значимые цели. Если какое-либо конкретное исключение, которое вы ловите, "обрабатывается", просто повторяя действие, не нужно будет ничего делать блок catch. Тем не менее, было бы неплохо зарегистрировать тот факт, что произошло исключение.
другой пример: среда CLR 2.0 изменила способ обработки необработанных исключений в потоке финализатора. До 2.0 процесс был разрешен, чтобы пережить этот сценарий. В текущей среде CLR процесс завершается в случае необработанного исключения в потоке финализатора.
имейте в виду, что вы должны реализовать только финализатор, если он вам действительно нужен, и даже тогда вы следует сделать как можно меньше в финализаторе. Но если любая работа, которую должен сделать ваш финализатор, может вызвать исключение, вам нужно выбрать между меньшим из двух зол. Вы хотите закрыть приложение из-за необработанного исключения? Или вы хотите продолжить в более или менее неопределенном состоянии? По крайней мере, теоретически последнее может быть меньшим из двух зол в некоторых случаях. В этом случае пустой блок catch предотвратит завершение процесса.
Я имею в виду, например, иногда вы хотите получить дополнительную информацию откуда-то (веб-сервис, база данных), и вам действительно все равно, получите ли вы эту информацию или нет. Поэтому вы пытаетесь получить его, и если что-то произойдет, это нормально, я просто добавлю "catch (исключение игнорируется) {}" и это всеИтак, ваш пример, это плохая идея в этом случае, потому что вы ловите и игнорируя все исключения. Если бы вы ловили только
EInfoFromIrrelevantSourceNotAvailableи игнорируя его, что было бы хорошо, но это не так. Вы также игнорируетеENetworkIsDown, что может быть или не быть важным. Ты игнорируешьENetworkCardHasMeltedиEFPUHasDecidedThatOnePlusOneIsSeventeen, которые почти наверняка важно.пустой блок catch не является проблемой, если он настроен только на catch (и игнорирует) исключения определенных типов, которые, как вы знаете, не имеют значения. Ситуации, в которых это хорошая идея, чтобы подавить и молча игнорировать все исключения, не останавливаясь, чтобы изучить их сначала, чтобы увидеть, является ли они ожидаемы / нормальны / неуместны или нет, чрезвычайно редки.
вы никогда не должны иметь пустой блок catch. Это как скрывать ошибку, о которой вы знаете. По крайней мере, вы должны написать исключение из файла журнала, чтобы просмотреть его позже, если у вас есть время.
есть ситуации, когда вы можете использовать их, но они должны быть очень нечастыми. Ситуации, где я мог бы использовать один включают в себя:
ведение журнала исключений; в зависимости от контекста вы можете захотеть, чтобы вместо этого было опубликовано необработанное исключение или сообщение.
циклические технические ситуации, такие как рендеринг или обработка звука или обратный вызов listbox, где само поведение продемонстрирует проблему, бросая исключение, просто встанет на пути, и регистрация исключения, вероятно, просто приведет к появлению 1000 сообщений "failed to XXX".
программы не может сбой, хотя они все равно должны по крайней мере регистрировать что-то.
для большинства приложений winforms я обнаружил, что достаточно иметь один оператор try для каждого пользовательского ввода. Я использую следующие методы: (AlertBox-это просто быстрый MessageBox.Показать обертку)
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, что может быть лучше для рендеринга вызовов, так что исключение не генерирует бесконечное количество сообщений.
Если вы не знаете, что делать в блок catch, вы можете просто войти это исключение, но не оставляйте его пустым.
try { string a = "125"; int b = int.Parse(a); } catch (Exception ex) { Log.LogError(ex); }
Comments