Что вы думаете о лучшей практике «Не ловить неожиданные исключения»? - PullRequest
7 голосов
/ 25 февраля 2009

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

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

У вас огромный сервер. Миллион строк кода.

При запуске загружает всех клиентов в свой локальный кеш.

Для меня имеет смысл написать следующее:

           foreach (string CustomerID in Customers)
                try
                {
                    LoadCustomer(CustomerID);
                }
                catch (Exception ex) // blind catch of all exceptions
                {
                    // log the exception, and investigate later.

                }

Без слепой уловки, если не загрузить ни одного Клиента, просто произойдет сбой всего сервера.

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

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

Есть что-то, что я здесь пропускаю? Известны ли лучшие практики (кроме стратегии «никогда не поймать неожиданное исключение»?)

Лучше ли перехватывать исключение в методе LoadCustomer (), отбрасывать оттуда «CustomerLoadException» и перехватывать CustomerLoadException вместо всех исключений в вызывающем коде?

Ответы [ 14 ]

0 голосов
/ 25 февраля 2009

Вы прекрасно ловите все исключения (но не ошибки), когда знаете, какие объекты и ресурсы могут быть затронуты, и удаляете все эти объекты.

Так что в вашем случае вы могли бы быть в порядке, чтобы обработать исключение, превращающее весь процесс в noop. Но вы должны быть уверены, что: - никакие другие общие ресурсы не являются эффективными (например, Hibernate Session, который может быть мертв после исключения) - полное (транс) действие отменяется не только половиной. Это означает, что такая обработка исключений может появляться только в особых местах, обычно непосредственно «под» пользовательским интерфейсом. Пример: пользователь нажимает кнопку, которая должна загрузить клиента, изменить его адрес и сохранить его снова. Если что-то пойдет не так, вы можете поймать исключение, не допустить выполнения всех оставшихся шагов, выбросить объект customer и представить сообщение с надписью: извините, не сработало.

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

Итак, правило таково: определите слой, где вы управляете транзакциями. Это должен быть слой, который ловит исключения. Может быть SwingActions, может быть Threads, может быть public void main, может быть внутри цикла, как в вашем примере.

0 голосов
/ 25 февраля 2009

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

Это действительно лучше?

0 голосов
/ 25 февраля 2009

Я не очень опытен в этой области. Однако мне кажется, что: 1. Есть некоторые исключения почти из любого правила. Знать, когда нарушать правило, важно. 2. В случае обработки исключений почти никогда не рекомендуется слепо отлавливать исключения. Это потому, что вы можете обнаружить некоторые действительно неожиданные ошибки.

Например, в Python (как минимум 2.5.2), перехват вслепую позволит мне перехватить сигнал ctrl + c (Linux). Это означает, что я не могу закрыть приложение в чрезвычайной ситуации.

  1. Для кода вашего веб-сервера вы можете выполнить одно из следующих действий:
    + Используйте пользовательское исключение, которое выдается, если клиенту не удается загрузить и зарегистрировать / исправить это.
    + Используйте обработку исключений на более глубоком уровне кода и обрабатывайте его там.
0 голосов
/ 25 февраля 2009

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

      foreach (string CustomerID in Customers)
            try
            {
                LoadCustomer(CustomerID);
            }
            catch (Exception ex) // blind catch of all exceptions
            {
                if (ex is OutOfMemoryException || ex is StackOverflowException ||...)
                     throw;
                // log the exception, and investigate later.

            }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...