Я думал об этом и не смог придумать пример. Почему кто-то хочет поймать исключение и ничего не делать с этим? Можете привести пример? Может быть, это просто то, что никогда не должно быть сделано.
Я думал об этом и не смог придумать пример. Почему кто-то хочет поймать исключение и ничего не делать с этим? Можете привести пример? Может быть, это просто то, что никогда не должно быть сделано.
Ответы:
Я делаю это все время с такими вещами, как ошибки преобразования в D:
import std.conv, std.stdio, std.exception;
void main(string[] args) {
enforce(args.length > 1, "Usage: foo.exe filename");
double[] nums;
// Process a text file with one number per line into an array of doubles,
// ignoring any malformed lines.
foreach(line; File(args[1]).byLine()) {
try {
nums ~= to!double(line);
} catch(ConvError) {
// Ignore malformed lines.
}
}
// Do stuff with nums.
}
Тем не менее, я думаю, что все блоки catch должны содержать что-то , даже если это просто комментарий, объясняющий, почему вы игнорируете исключение.
Изменить: Я также хочу подчеркнуть, что, если вы собираетесь сделать что-то подобное, вы должны быть осторожны, чтобы поймать только конкретное исключение, которое вы хотите игнорировать. Делать старый catch {}
добрый почти всегда плохо.
Один пример, где я думаю, что можно просто проглотить исключение, ничего не делая, даже регистрируя исключение, находится внутри самого кода регистрации.
Если вы пытались что-то зарегистрировать и получили исключение, вы ничего не можете с этим поделать:
Это оставляет вам возможность «наименьшего количества зла» тихо проглотить его, позволяя приложению продолжать выполнять свою основную работу, но ставя под угрозу возможность устранения неполадок.
Если исключение выдается операцией, которая в любом случае была необязательной, делать нечего. Это может быть бесполезно для регистрации. В этом случае вы можете просто поймать это и ничего не делать.
Если вы делаете это, добавьте комментарий. Всегда комментируйте все, что похоже на ошибку (падение в switch
операторе, пустой catch
блок, назначение в условии).
Вы можете утверждать, что это не правильное использование исключений, но это другой вопрос.
Пустые catch
блоки являются запахом кода на большинстве языков. Основная идея состоит в том, чтобы использовать исключения для исключительных ситуаций, а не использовать их для логического контроля. Все исключения должны быть где-то обработаны.
Как следствие этого подхода, когда вы программируете один конкретный прикладной уровень, у вас есть несколько вариантов:
Это действительно не оставляет места для ничего не делать, пустые catch
блоки.
ИЗМЕНЕНО ДЛЯ ДОБАВЛЕНИЯ : предположим, что вы программируете на языке, в котором выдача исключений является обычным способом управления логикой программы (одна из альтернатив goto
). Тогда пустой catch
блок в программе, написанной на этом языке, очень похож на пустой else
блок в традиционном языке (или вообще без else
блока). Однако я считаю, что это не тот стиль программирования, который рекомендован сообществами разработчиков на C #, Java или C ++.
В некоторых случаях Java требует от вас обработки исключения, которое ни при каких обстоятельствах не может произойти. Рассмотрим этот код:
try {
bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}
Каждая реализация платформы Java должна поддерживать следующие стандартные кодировки.
...
UTF-8,
Не нарушая вашу платформу Java, просто невозможно вызвать это исключение. Так зачем заниматься этим? Но вы не можете просто опустить предложение try-catch.
throw new Error(e)
чтобы быть абсолютно уверенным, что я ничего не пропустил (или сообщить о фактически сломанной платформе).
Как правило, нет. Вы либо хотите выбросить исключение в стек, либо записать, что произошло.
Тем не менее, я часто делаю это, когда разбираю строки и конвертирую в числа (особенно в картографических проектах, которые имеют одноразовое использование и отбрасывают разнообразие).
boolean isNonZeroNumber = false;
try {
if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
b = true;
}
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}
return b;
В некоторых случаях исключение вовсе не является исключением; на самом деле, это ожидается. Рассмотрим этот пример:
/* Check if the process is still alive; exitValue() throws an exception if it is */
try {
p.exitValue();
processPool.remove(p);
}
catch (IllegalThreadStateException e) { /* expected behaviour */ }
Поскольку в java.lang.Process () нет метода isAlive (), единственный способ проверить, все еще ли он жив, - это вызвать exitValue (), который выдает исключение IllegalThreadStateException, если процесс все еще выполняется.
По моему скромному опыту, редко это хорошо. Ваш пробег может варьироваться, хотя.
Почти каждый раз, когда я видел это в нашей кодовой базе, это происходило потому, что я обнаружил ошибку, которую скрытое исключение. Другими словами, не предоставляя никакого кода, приложение не может указать ошибку или выполнить другое действие.
Иногда, например, на уровнях API вы не хотите или не можете пропустить исключения, так что в этом случае я стараюсь поймать самые общие, а затем записать их в журнал. Еще раз, по крайней мере, дать шанс сеансу отладки / диагностики.
Как правило, если он должен быть пустым, я по крайней мере ставлю какое-либо утверждение, поэтому, по крайней мере, что-то происходит во время сеанса отладки. Тем не менее, если я не могу справиться с этим, я склонен опустить их полностью.
ИМО есть одно место, где пустые операторы catch в порядке. В тестовых случаях, когда вы ожидаете исключения:
try
{
DoSomething(); //This should throw exception if everything works well
Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
//Expected to get here
}
Я полагаю, что в некоторых случаях оправданно иметь пустое предложение catch - это случаи, когда вы хотите, чтобы код продолжал работать, если какая-то конкретная операция завершается неудачно. Тем не менее, я думаю, что этот шаблон можно легко использовать слишком часто, поэтому каждое использование должно быть тщательно изучено, чтобы убедиться, что нет лучшего способа справиться с ним. В частности, этого никогда не следует делать, если оно оставляет программу в несовместимом состоянии или может привести к сбою какой-либо другой части кода в дальнейшем.
Я не верю в отсутствие какого-либо уровня оповещения, когда возникает исключение - не должна ли одна из целей программирования быть в улучшении кода? Если исключение возникает в 10% случаев, и вы никогда не знаете об этом, тогда исключение всегда будет таким плохим или хуже.
Тем не менее, я вижу другую сторону, что если исключение не наносит реального ущерба при обработке кода, то зачем подвергать его воздействию пользователя. Решение, которое я обычно реализую, заключается в том, чтобы оно регистрировалось моим классом регистратора (то есть в каждом отдельном классе, который я когда-либо писал на работе).
Если это мягкое исключение, то я вызываю метод моего Logger .Debug (); в противном случае Logger.Error () (и (возможно) throw).
try
{
doWork();
}
catch(BenignException x)
{
_log.Debug("Error doing work: " + x.Message);
}
Между прочим, в моей реализации моего регистратора вызов метода .Debug () будет регистрировать его только в том случае, если в моем файле App.Config указано, что уровень журнала выполнения программы находится в режиме отладки.
Проверка существования является хорошим вариантом использования:
// If an exception happens, it doesn't matter. Log the initial value or the new value
function logId(person) {
let id = 'No ID';
try {
id = person.data.id;
} catch {}
console.log(id);
}
Другой случай, когда используется finally
предложение:
function getter(obj){}
function objChecker()
{
try
{
/* Check argument length and constructor type */
if (getter.length === 1 && getter.constructor === Function)
{
console.log("Correct implementation");
return true;
}
else
{
console.log("Wrong implementation");
return false;
}
}
catch(e)
{
}
finally
{
console.log(JSON.stringify(getter))
}
}
// Test the override of the getter method
getter = getter;
objChecker();
getter = [];
objChecker();
getter = {};
objChecker();
getter = RegExp;
objChecker();
getter = Function;
objChecker();
Существует предложение разрешить исключение привязки улова в ECMAScript, которая относится к этому и аналогичным случаям использования.
Рекомендации
Единственный раз, когда мне действительно нужно было сделать что-то подобное, было с классом журналирования для консольного приложения. Был глобальный обработчик верхнего уровня, который отправлял ошибку в STDOUT, записывал ошибку в файл, а затем закрывал приложение с кодом ошибки> 0.
Проблема заключалась в том, что иногда запись в файл не выполнялась. Права доступа к каталогу не позволили вам записать файл, файл был заблокирован исключительно. Если это произошло, я не смог бы обработать исключение так же, как в другом месте (поймать, записать соответствующие подробности , перенести в лучший тип исключения и т. Д.), Потому что регистрация подробностей исключения вынудила регистратор выполнить те же действия ( пытается записать в файл), который уже не удалось. Когда они снова потерпели неудачу ... Вы видите, куда я иду. Это входит в бесконечный цикл.
Если вы отбросите некоторые из блоков try {}, вы можете получить исключение, появившееся в окне сообщения (а не то, что вы хотите для приложения конфигурирования без вывода сообщений). Так что в том методе, который записывает в файл журнала, у меня есть пустой обработчик catch. Это не скрывает ошибку, поскольку вы по-прежнему получаете код ошибки> 0, она просто останавливает бесконечный цикл и позволяет приложению корректно завершить работу.
Конечно, есть комментарий, объясняющий, почему он пуст.
(Я собирался опубликовать это раньше, я просто боялся быть в забвении. Хотя я не единственный, хотя ...)
Это нормально в ситуации, когда какая-то последовательность должна быть выполнена независимо от того, какая часть критична в конце.
Например. В управлении движением связь хоста с контроллером. В аварийных ситуациях есть ряд подготовительных шагов, чтобы прервать движение, остановить формирование траектории, замедлить двигатели, включить обрывы, отключить усилитель, и после этого вы должны отключить питание шины. Все должно происходить последовательно, и в случае сбоя одного из шагов остальные шаги должны быть выполнены в любом случае, даже с принятым риском повреждения оборудования. Скажем, даже если все вышеперечисленное не сработало, отключение питания шины должно произойти в любом случае.
Изящное закрытие системных ресурсов для восстановления после ошибки
Например. Если вы используете службу в фоновом режиме , что не обеспечивает обратную связь с пользователем, вы не можете нажать индикацию ошибки пользователя , но вы делаете необходимость закрыть ресурсы используются в изящной манере.
try
{
// execution code here
}
catch(Exception e)
{
// do nothing here
}
finally
{
// close db connection
// close file io resource
// close memory stream
// etc...
}
В идеале вы должны использовать функцию catch в режиме отладки, чтобы перехватывать ошибки и выводить их на консоль или в файл журнала для тестирования. В производственной среде обычно ожидается, что фоновые службы не будут прерывать пользователя при возникновении ошибки, поэтому вывод ошибок должен быть подавлен.