Есть ли веская причина игнорировать пойманное исключение? - PullRequest
49 голосов
/ 15 октября 2008

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

Exceptions.DontSwallowErrorsCatchingNonspecificExceptionsRule  : 2106 defects 

Разработчики уверяют меня, что у них есть веская причина для всех пустых блоков catch, что иногда попытка с пустыми блоками catch просто игнорирует бесполезные исключения и предотвращает сбой приложения. Я чувствую, что это полицейский и полный BS. Некоторые из примеров, которые я на самом деле искал, были вызовы базы данных, где запись была сохранена в базе данных, и в этом случае, если исключение было проигнорировано, пользователь вернул бы нормальное приглашение, подумал, что все в порядке, и продолжил их работа. На самом деле их работа никогда не была сохранена. Я думаю, что это абсолютно самая ужасная ошибка. В этом случае, они совершенно не правы, бросая этот код в попытке с пустым блоком catch. Но мой вопрос: "Это когда-либо приемлемо в ЛЮБОЙ ситуации?" Я думаю, что нет, но я, как известно, был неправ.

Ответы [ 24 ]

55 голосов
/ 15 октября 2008

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

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

try {
  // Do something that might generate an exception
} catch (System.InvalidCastException ex) {
  // This exception is safe to ignore due to...
} catch (System.Exception ex) {
  // Exception handling
}

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

16 голосов
/ 15 октября 2008

Я не ловлю исключения, если не планирую что-то с ними делать. Игнорирование их ничего не делает с ними.

12 голосов
/ 15 октября 2008

Я иногда использую WebControl, который не является обязательным для отображения страницы. Если это не удается, я не хочу, чтобы страница не отображалась. Примером некритического WebControl будет тот, который отображает рекламу.

Однако я регистрирую ошибку. Я просто не выбрасываю это.

11 голосов
/ 15 октября 2008

Мне кажется, что любой пустой блок Catch нуждается в комментарии.

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

Кроме того, вы не хотели бы делать это общим "catch (Exception e) {}".

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

8 голосов
/ 15 октября 2008

Обычно нет, фактически нет в 99% всех случаев, НО

Есть исключения. В одном проекте, над которым я работал, мы использовали стороннюю библиотеку для работы с устройством TWAIN. Это было глючно и при некоторых аппаратных комбинациях выдает ошибку нулевого указателя. Однако мы никогда не находили никаких обстоятельств, когда ему не удалось отсканировать документ до того, как он это сделал, поэтому отловить исключение было вполне рациональным.

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

8 голосов
/ 15 октября 2008

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

public void testSomething(){
    try{
        fooThatThrowsAnException(parameterThatCausesTheException);
        fail("The method didn't throw the exception that we expected it to");
    } catch(SomeException e){
        // do nothing, as we would expect this to happen, if the code works OK.
    }
}

Обратите внимание, что хотя блок catch ничего не делает, он объясняет почему.

Сказав это, более поздние среды тестирования (Junit4 & TestNG) позволяют вам указать ожидаемое исключение, которое приводит к чему-то вроде этого ...

@Test(expected = SomeException.class)
public void testSomething(){
    fooThatThrowsAnException(parameterThatCausesTheException);
    fail("The method didn't throw the exception that we expected it to");
}
7 голосов
/ 15 октября 2008

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

6 голосов
/ 15 октября 2008

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

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

5 голосов
/ 15 октября 2008

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

5 голосов
/ 15 октября 2008

Конечно, есть обстоятельства, когда можно поймать конкретное исключение и ничего не делать. Вот тривиальный пример:

    public FileStream OpenFile(string path)
    {
        FileStream f = null;
        try
        {
            f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
        }
        catch (FileNotFoundException)
        {
        }
        return f;
    }

Вы также можете написать метод так:

    public FileStream OpenFile(string path)
    {
        FileStream f = null;
        FileInfo fi = new FileInfo(path);
        if (fi.Exists)
        {
            f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);                
        }
        return f;
    }

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

Есть причины , а не , чтобы сделать это, конечно. В .NET исключения являются вычислительно дорогими, поэтому вы хотите избегать всего, что их выбрасывает. (В Python, где исключения дешевы, обычно используют исключения для таких вещей, как вырывание циклов.)

Но это игнорирует специфическое исключение. Этот код:

catch
{
}

непростительно.

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

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

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