exceptions - try catch finally java




Почему я не должен обертывать каждый блок в «try»-«catch»? (10)

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

Я только что написал « Вы должны ВСЕГДА переносить вызовы, которые могут бросать попытки, блокировать блоки. »на этот вопрос, и ему сказали, что это« замечательно плохой совет »- я хотел бы понять, почему.


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

Это удобно по трем причинам: это удобно, потому что у вас есть одно место для сообщения об ошибке: блок (ы) SaveDocument() ). Нет необходимости повторять это во всех суб-методах, и это то, что вы хотите в любом случае: одно место, чтобы дать пользователю полезную диагностику о чем-то, что пошло не так.

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

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

int ret = SaveFirstSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveSecondSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveThirdSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

Вот как это можно было бы написать с исключениями:

// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();

Теперь гораздо яснее, что происходит.

Примечание. Безопасный код исключения может быть более сложным для записи другими способами: вы не хотите утечки какой-либо памяти, если выбрано исключение. Убедитесь, что вы знаете о контейнерах RAII , STL, интеллектуальных указателях и других объектах, которые освобождают свои ресурсы в деструкторах, поскольку объекты всегда удаляются до исключения.


Вам не нужно скрывать каждую часть кода внутри try-catch . Основное использование блока try-catch - обработка ошибок и получение ошибок / исключений в вашей программе. Некоторое использование try-catch -

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

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

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

Исключения в 100-1000 раз медленнее, чем обычный код, и их никогда не следует отказывать. Также не создавайте исключение и не бросайте его. Это очень неприятно. Исключения пойманы, поэтому их можно исправить с помощью обычного кода.

Этот метод был использован для быстрой стабилизации багги-приложения в компании Fortune 500, разработанной 12 Devs в течение 2 лет. Используя это, я определил, исправил, построил тесты и развернул 3000 исправлений за 4 месяца, и в этом случае система больше не сообщала о каких-либо исключениях, поскольку все они были обработаны. В среднем это составляет каждые 15 минут в среднем за 4 месяца.


Если вы хотите проверить результат каждой функции, используйте коды возврата.

Цель Исключения заключается в том, что вы можете часто тестировать результаты МЕНЬШЕ. Идея состоит в том, чтобы отделить исключительные (необычные, более редкие) условия от вашего более обычного кода. Это упрощает и упрощает обычный код, но все же способно справляться с этими исключительными условиями.

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


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

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


Лучший совет, который я слышал, заключается в том, что вы должны только когда-либо перехватывать исключения в точках, где вы можете разумно что-то делать с исключительным условием, и что «catch, log and release» не является хорошей стратегией (если это иногда неизбежно в библиотеках).


Помимо вышеупомянутого совета, лично я использую некоторые try + catch + throw; по следующей причине:

  1. На границе другого кодера я использую try + catch + throw в коде, написанном мной, перед тем как исключение будет передано вызывающему, которое написано другими, это дает мне возможность узнать о некотором условии ошибки, имевшем место в моем коде, и это место намного ближе к коду, изначально генерирующему исключение, чем ближе, тем легче найти причину.
  2. На границе модулей, хотя другой модуль может быть написан моим же человеком.
  3. Learning + Debug, в этом случае я использую catch (...) в C ++ и catch (Exception ex) в C #, для C ++ стандартная библиотека не бросает слишком много исключений, поэтому этот случай встречается редко в C ++. Но обычное место в C #, C # имеет огромную библиотеку и зрелую иерархию исключений, код библиотеки C # бросает тонны исключения, теоретически я (и вы) должен знать все исключения из вызываемой вами функции и знать причину / случай, почему эти исключения выбрасываются и умеют обрабатывать их (проезжать мимо или ловить и обрабатывать их на месте) изящно. К сожалению, на самом деле очень сложно узнать все о потенциальных исключениях, прежде чем я напишу одну строку кода. Поэтому я улавливаю все и позволяю моему коду говорить вслух путем ведения журнала (в среде продукта) / assert (в среде разработки), когда действительно происходит какое-либо исключение. Таким образом, я постепенно добавляю код обработки исключений. Я знаю, что это хорошо, но на самом деле это работает для меня, и я не знаю лучшего способа решить эту проблему.

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


Херб Саттер написал об этой проблеме. Конечно, стоит читать.
Тизер:

«Написание исключающего код кода в основном заключается в написании« try »и« catch »в правильных местах». Обсудить.

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

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


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

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

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





try-catch