Я нашел такой код в одном из наших проектов:
SomeClass QueryServer(string args)
{
try
{
return SomeClass.Parse(_server.Query(args));
}
catch (Exception)
{
return null;
}
}
Насколько я понимаю, подавление ошибок, подобных этой, является плохой практикой, поскольку она уничтожает полезную информацию из исключения исходного сервера и заставляет код продолжаться, когда он фактически должен завершиться.
Когда уместно полностью подавить все ошибки, подобные этой?
Ответы:
Представьте код с тысячами файлов, используя несколько библиотек. Представьте, что все они закодированы так.
Представьте, например, что обновление вашего сервера приводит к исчезновению одного файла конфигурации; и теперь все, что у вас есть, это трассировка стека, исключение нулевого указателя, когда вы пытаетесь использовать этот класс: как бы вы решили это? Это может занять несколько часов, в течение которых, по крайней мере, простая регистрация трассировки необработанного стека файла, не найденного [путь к файлу], может позволить вам на мгновение разрешить проблему.
Или еще хуже: сбой в одной из библиотек, которые вы используете после обновления, что впоследствии приводит к сбою кода. Как вы можете отследить это обратно в библиотеку?
Даже без надежной обработки ошибок просто
или
может сэкономить вам часы времени.
Но есть некоторые случаи, когда вы действительно можете игнорировать исключение и возвращать ноль, как это (или ничего не делать). Особенно, если вы интегрируетесь с каким-то плохо разработанным унаследованным кодом, и это исключение ожидается как обычный случай.
На самом деле, когда вы делаете это, вы просто должны задаться вопросом, действительно ли вы игнорируете исключение или «правильно обрабатываете» для своих нужд. Если возвращение null «правильно обрабатывает» ваше исключение в данном случае, сделайте это. И добавьте комментарий, почему это правильно.
Лучшие практики - это вещи, которым нужно следовать в большинстве случаев, может быть, 80%, может быть, 99%, но вы всегда найдете один крайний случай, когда они не применяются. В этом случае оставьте комментарий, почему вы не следуете практике для других (или даже для себя), которые будут читать ваш код несколько месяцев спустя.
источник
Есть случаи, когда этот шаблон полезен - но они обычно используются, когда сгенерированное исключение никогда не должно было быть (то есть, когда исключения используются для нормального поведения).
Например, представьте, что у вас есть класс, который открывает файл и сохраняет его в возвращаемом объекте. Если файл не существует, вы можете считать, что это не ошибка, вы возвращаете ноль и позволяете пользователю создать новый файл. Метод открытия файла может выдать исключение, чтобы указать, что файла нет, поэтому молча перехватить его может быть допустимой ситуацией.
Тем не менее, это не часто, вы захотите сделать это, и если код завален таким шаблоном, вы хотели бы иметь дело с этим сейчас. По крайней мере, я бы ожидал, что такой тихий улов напишет строку журнала, сообщающую, что это то, что произошло (у вас есть трассировка, верно), и комментарий, объясняющий это поведение.
источник
null
если это лучшее, что может предложить выбранный вами язык.Это на 100% зависит от контекста. Если у вызывающей стороны такой функции есть требование отображать или регистрировать ошибки где-либо, то это явно ерунда. Если вызывающая сторона игнорирует все ошибки или сообщения об исключениях, то нет смысла возвращать исключение или его сообщение. Когда требование состоит в том, чтобы код завершался только без указания причины, вызов
вероятно, будет достаточно. Вы должны подумать, не затруднит ли пользователь найти причину ошибки - если это так, то это неправильная форма обработки ошибок. Однако, если вызывающий код выглядит так
тогда вы должны поспорить с разработчиком во время проверки кода. Если кто-то реализует такую форму обработки без ошибок только потому, что ему лень выяснять правильные требования, то этот код не должен поступать в производство, и автора кода следует учить о возможных последствиях такой лени ,
источник
За годы, которые я потратил на программирование и разработку систем, есть только две ситуации, в которых я нашел данный шаблон полезным (в обоих случаях подавление содержало также запись в журнал сгенерированного исключения, я не считаю простой перехват и
null
возврат хорошей практикой). ).Две ситуации следующие:
1. Когда исключение не считалось исключительным состоянием
Это когда вы выполняете операцию с некоторыми данными, которые могут выдавать, вы знаете, что они могут выдавать, но вы все равно хотите, чтобы ваше приложение продолжало работать, потому что вам не нужны обработанные данные. Если вы получаете их, это хорошо, если вы не получаете, это тоже хорошо.
Некоторые необязательные атрибуты класса могут иметь в виду.
2. Когда вы предоставляете новую (лучше, быстрее?) Реализацию библиотеки с использованием интерфейса, уже используемого в приложении
Представьте, что у вас есть приложение, использующее какую-то старую библиотеку, которая не выдает исключений, но возвращает
null
ошибку. Итак, вы создали адаптер для этой библиотеки, в значительной степени копируя исходный API библиотеки, и используете этот новый (все еще не генерирующий) интерфейс в своем приложении иnull
сами выполняете проверки.Приходит новая версия библиотеки, или, возможно, совершенно другая библиотека, предлагающая те же функции, которая вместо возврата
null
s выдает исключения, и вы хотите использовать ее.Вы не хотите просачивать исключения в ваше основное приложение, поэтому вы подавляете их и регистрируете их в адаптере, который создаете, чтобы обернуть эту новую зависимость.
Первый случай не проблема, это желаемое поведение кода. Во второй ситуации, однако, если везде
null
возвращаемое значение библиотечного адаптера действительно означает ошибку, рефакторинг API для генерирования исключения и перехвата его вместо проверкиnull
может быть (и обычно для кода) хорошей идеей.Я лично использую исключение исключений только для первого случая. Я использовал его только для второго случая, когда у нас не было бюджета, чтобы остальная часть приложения работала с исключениями вместо
null
s.источник
Хотя кажется логичным сказать, что программы должны отлавливать только те исключения, которые они знают, как обрабатывать, и не могут знать, как обрабатывать исключения, которые не были ожидаемы программистом, такое утверждение игнорирует тот факт, что многие операции могут завершиться с ошибкой. практически неограниченное количество способов, которые не имеют побочных эффектов, и что во многих случаях надлежащая обработка для подавляющего большинства таких сбоев будет идентичной; точные детали ошибки не будут иметь значения, и, следовательно, не должно иметь значения, ожидал ли их программист.
Если, например, целью функции является чтение файла документа в подходящий объект и либо создание нового окна документа, чтобы показать этот объект, либо отчет пользователю о том, что файл не может быть прочитан, попытка загрузить файл недопустимый файл документа не должен вызывать сбой приложения - вместо этого должно отображаться сообщение, указывающее на проблему, но позволить остальной части приложения продолжить нормальную работу, если по какой-либо причине попытка загрузить документ не повредила состояние чего-либо еще в системе ,
По сути, правильная обработка исключения часто будет зависеть в меньшей степени от типа исключения, чем от места, где оно было сгенерировано; если ресурс защищен блокировкой чтения-записи, и в методе, который получил блокировку для чтения, генерируется исключение, обычно правильное поведение должно состоять в снятии блокировки, поскольку метод не может ничего сделать с ресурсом , Если во время получения блокировки для записи возникает исключение, блокировку часто следует аннулировать, поскольку защищенный ресурс может находиться в недопустимом состоянии; если у блокирующего примитива нет состояния «недействительно», следует добавить флаг для отслеживания такой аннулирования. Снятие блокировки без ее аннулирования - это плохо, потому что другой код может видеть защищенный объект в недопустимом состоянии. Однако, оставляя замок висящим, или правильное решение. Правильное решение состоит в том, чтобы аннулировать блокировку так, чтобы любые ожидающие или будущие попытки получения немедленно потерпели неудачу.
Если выясняется, что недействительный ресурс будет заброшен до того, как будет предпринята какая-либо попытка его использовать, нет никаких причин, по которым он должен закрыть приложение. Если недействительный ресурс имеет решающее значение для продолжения работы приложения, приложение должно быть закрыто, но аннулирование ресурса, вероятно, приведет к этому. Код, получивший исходное исключение, часто не имеет возможности узнать, какая ситуация применима, но если он делает недействительным ресурс, он может гарантировать, что в любом случае будет выполнено правильное действие.
источник
Поглощение такого рода ошибок не особенно полезно никому. Да, первоначальный абонент может не заботиться об исключении, но кто-то еще может .
Тогда что они делают? Они добавят код для обработки исключения, чтобы увидеть, какой вариант исключения они получают. Отлично. Но если обработчик исключений остается, исходный вызывающий объект больше не возвращается в ноль, и что-то ломается в другом месте.
Даже если вы знаете, что какой-то вышестоящий код может выдать ошибку и, таким образом, вернуть значение null, с вашей стороны было бы серьезно инертно не пытаться, по крайней мере, попытаться предотвратить исключение в вызывающем коде IMHO.
источник
Я видел примеры, когда сторонние библиотеки имели потенциально полезные методы, за исключением того, что в некоторых случаях они генерируют исключения, которые должны работать для меня. Что я могу сделать?
Например, метод библиотеки
возвращает первый foo, но если его нет, он генерирует исключение. Но мне нужен метод возврата первого foo или null. Итак, я пишу это:
Не аккуратно. Но иногда прагматичное решение.
источник