Руби QuickRef Райана Дэвиса говорит (без объяснения причин):
Не спасайте Исключение. КОГДА-ЛИБО. или я тебя зарежу.
Почему бы нет? Что правильно сделать?
Руби QuickRef Райана Дэвиса говорит (без объяснения причин):
Не спасайте Исключение. КОГДА-ЛИБО. или я тебя зарежу.
Почему бы нет? Что правильно сделать?
Ответы:
TL; DR : использовать
StandardError
вместо этого для общего отслеживания исключений. Когда исходное исключение повторно вызывается (например, при спасении, чтобы регистрировать только исключение), спасениеException
, вероятно, в порядке.Exception
является корнем иерархии исключений в Ruby , поэтому , когда выrescue Exception
вы спасти от всего , в том числе подклассов , таких какSyntaxError
,LoadError
иInterrupt
.Спасение не
Interrupt
позволяет пользователю использовать CTRLCдля выхода из программы.Спасение не
SignalException
позволяет программе правильно реагировать на сигналы. Это будет неубиваемо, кроме какkill -9
.Спасение
SyntaxError
означает,eval
что неудачники будут делать это молча.Все это можно показать, запустив эту программу, и пытается CTRLCили
kill
ему:Спасение от
Exception
даже не по умолчанию. делане спасает от
Exception
, спасает отStandardError
. Как правило, вы должны указывать что-то более конкретное, чем значение по умолчаниюStandardError
, но спасение отException
расширения, а не сужения области действия, может привести к катастрофическим результатам и сделать поиск ошибок чрезвычайно трудным.Если у вас есть ситуация, когда вы хотите спастись,
StandardError
и вам нужна переменная с исключением, вы можете использовать эту форму:что эквивалентно:
Один из немногих распространенных случаев
Exception
, из которых целесообразно спасать, - для целей регистрации / отчетности, и в этом случае вы должны немедленно повторно вызвать исключение:источник
Throwable
в javaADAPTER_ERRORS = [::ActiveRecord::StatementInvalid, PGError, Mysql::Error, Mysql2::Error, ::ActiveRecord::JDBCError, SQLite3::Exception]
и тогдаrescue *ADAPTER_ERRORS => e
Реальное правило: Не выбрасывать исключения. Объективность автора вашей цитаты сомнительна, о чем свидетельствует тот факт, что она заканчивается
Конечно, имейте в виду, что сигналы (по умолчанию) генерируют исключения, и обычно длительные процессы завершаются с помощью сигнала, поэтому перехват исключений и не прекращение исключений сигналов очень затруднит остановку вашей программы. Так что не делайте этого:
Нет, правда, не делай этого. Даже не запускайте это, чтобы увидеть, работает ли оно.
Однако, скажем, у вас есть многопоточный сервер, и вы хотите, чтобы все исключения не:
thread.abort_on_exception = true
).Тогда это вполне приемлемо в вашей ветке обработки соединений:
Вышесказанное работает с вариантом обработчика исключений по умолчанию в Ruby, с тем преимуществом, что он также не убивает вашу программу. Rails делает это в своем обработчике запросов.
Исключения сигналов возникают в основном потоке. Фоновые потоки не получат их, поэтому нет смысла пытаться их там поймать.
Это особенно полезно в производственной среде, где вы не хотите, чтобы ваша программа просто остановилась, когда что-то пойдет не так. Затем вы можете взять дампы стека в своих журналах и добавить к своему коду, чтобы обработать конкретное исключение дальше по цепочке вызовов и более изящно.
Также обратите внимание, что существует другая идиома Ruby, которая имеет почти такой же эффект:
В этой строке, если
do_something
возникает исключение, оно перехватывается Ruby, выбрасывается иa
назначается"something else"
.Как правило, не делайте этого, за исключением особых случаев, когда вы знаете, что вам не нужно беспокоиться. Один пример:
debugger
Функция довольно хороший способ , чтобы установить точку останова в коде, но при работе вне отладчика, и Rails, он вызывает исключение. Теперь, теоретически, вы не должны оставлять отладочный код в своей программе (pff! Никто не делает этого!), Но вы можете захотеть оставить его там какое-то время, но не запускать отладчик постоянно.Замечания:
Если вы запустили чужую программу, которая ловит исключения сигналов и игнорирует их (скажем, код выше), то:
pgrep ruby
илиps | grep ruby
найдите PID вашей программы-нарушителя и запуститеkill -9 <PID>
.Если вы работаете с чьей-либо программой, которая по какой-либо причине усеяна этими блоками игнорирования-исключения, то размещение этого в верхней части основной строки является одним из возможных отказов:
Это приводит к тому, что программа реагирует на обычные сигналы завершения, немедленно завершая работу, обходя обработчики исключений, без очистки . Так что это может привести к потере данных или тому подобное. Быть осторожен!
Если вам нужно сделать это:
вы можете сделать это:
Во втором случае
critical cleanup
будет вызываться каждый раз, независимо от того, выдано ли исключение.источник
kill -9
.ensure
завещание будет выполняться независимо от того, было ли возбуждено исключение или нет, тогда какrescue
завещание будет выполняться только в том случае, если было возбуждено исключение.TL; DR
Не делайте
rescue Exception => e
(и не поднимайте заново исключение) - иначе вы можете сойти с моста.Допустим, вы находитесь в машине (работает Руби). Вы недавно установили новое рулевое колесо с беспроводной системой обновления (которая использует
eval
), но вы не знали, что один из программистов испортил синтаксис.Вы находитесь на мосту и понимаете, что идете немного к перилам, поэтому вы поворачиваете налево.
упс! Это, вероятно, не хорошо ™, к счастью, Руби поднимает
SyntaxError
.Машина должна немедленно остановиться - верно?
Нет.
Вы заметили что - то не так, и вы хлопнуть на аварийных перерывов (
^C
:Interrupt
)Да - это не очень помогло. Вы довольно близко к рельсам, поэтому вы ставите машину в парк (
kill
ing:)SignalException
.В последнюю секунду вы вытаскиваете ключи (
kill -9
), и машина останавливается, вы врезаетесь в руль (подушка безопасности не может надуваться, потому что вы не грациозно остановили программу - вы ее остановили), и компьютер в задней части вашего автомобиля врезается в сиденье перед ним. Наполовину полная банка кока-колы проливает на бумаги. Продукты в задней части измельчены, и большинство из них покрыты яичным желтком и молоком. Автомобиль нуждается в серьезном ремонте и чистке. (Потеря данных)Надеюсь, у вас есть страховка (резервные копии). Ах да - потому что подушка безопасности не надулась, вы, вероятно, ранены (уволены и т. Д.).
Но ждать! Там в
Большепричины, почему вы можете захотеть использоватьrescue Exception => e
!Допустим, вы тот автомобиль, и вы хотите убедиться, что подушка безопасности надувается, если автомобиль превышает безопасный момент остановки.
Вот исключение из правила: Вы можете поймать его,
Exception
только если повторно вызовите исключение . Итак, лучшее правило - никогда не глотатьException
и всегда повторно выдавать ошибку.Но добавление аварийного восстановления легко забыть на языке, подобном Ruby, и создание правильного выражения перед повторным поднятием проблемы выглядит немного неСУХОЙ. И вы не хотите забывать это
raise
утверждение. И если вы это сделаете, удачи в попытке найти эту ошибку.К счастью, Ruby великолепен, вы можете просто использовать
ensure
ключевое слово, которое обеспечивает выполнение кода.ensure
Ключевое слово будет работать код независимо от того , что - если исключение, если один не является, единственным исключением является , если мир заканчивается (или другие маловероятные события).Boom! И этот код должен работать в любом случае. Единственная причина, по которой вы должны использовать
rescue Exception => e
это то, что вам нужен доступ к исключению или если вы хотите, чтобы код выполнялся только для исключения. И не забудьте повторно поднять ошибку. Каждый раз.Примечание: как указывал @Niall, всегда выполняйте . Это хорошо, потому что иногда ваша программа может лгать вам и не генерировать исключения, даже когда возникают проблемы. С критическими задачами, такими как надувные подушки безопасности, вы должны быть уверены, что это произойдет, несмотря ни на что. Из-за этого, проверяя каждый раз, когда автомобиль останавливается, выбрасывается ли исключение, хорошая идея. Несмотря на то, что накачивание подушек безопасности является довольно редкой задачей в большинстве контекстов программирования, на самом деле это довольно часто встречается в большинстве задач по очистке.
источник
ensure
касающаяся альтернативы,rescue Exception
вводит в заблуждение - пример подразумевает, что они эквивалентны, но, как уже говорилось,ensure
будет происходить независимо от того, есть ли исключение или нет, поэтому теперь ваши подушки безопасности будут надуваться, потому что вы разогнались на 5 миль в час, даже если ничего не пошло не так.Потому что это охватывает все исключения. Вряд ли ваша программа сможет восстановиться после любого из них.
Вы должны обрабатывать только исключения, которые вы знаете, как восстановить. Если вы не ожидаете какого-то исключения, не обрабатывайте его, громко вылетайте (записывайте подробности в журнал), затем диагностируйте журналы и исправляйте код.
Глотать исключения - это плохо, не делай этого.
источник
Это частный случай правила , что вы не должны поймать любое исключение вы не знаете , как обращаться. Если вы не знаете, как с этим справиться, всегда лучше позволить какой-то другой части системы перехватить и обработать ее.
источник
Я только что прочитал отличный пост в блоге об этом на honeybadger.io :
Исключение Руби против StandardError: Какая разница?
источник