Как бросить хорошие исключения?

public static byte[] intToBytes(int x) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DataOutputStream out = new DataOutputStream(bos);
    out.writeInt(x);
    out.close();
    byte[] int_bytes = bos.toByteArray();
    bos.close();
    return int_bytes;
}
13
задан 17 February 2009 в 21:30
поделиться

11 ответов

По-моему, функция должна выдать исключение, если она не может сдержать свое "обещание", если она должна нарушить свои "условия контракта". Подпись функции (имя и параметры) определяет свой контракт.

, Учитывая эти две функции членства:

const Apple* FindApple(const wchar_t* name) const;
const Apple& GetApple(const wchar_t* name) const;

названия этих функций, а также их возвращаемых значений указывают мне, что в случае FindApple функция совершенно способна к возврату ПУСТОГО УКАЗАТЕЛЯ, когда корректное яблоко не было найдено, но в случае [1 110] GetApple, Вы ожидаете, что яблоко возвратится. Если та вторая функция не может сдержать свое обещание, она должна выдать исключение.

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

Примечание, что в случае [1 111] FindApple, это до вызывающей стороны, чтобы решить, как обработать условие "не нахождения правильного яблока", потому что это больше не исключительное условие.

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

В конечном счете, исключение должно быть обработано, но только вызывающей стороной, которая знает, как обработать конкретное условие полезным способом . И я имею в виду это в самой широкой интерпретации: сервис, который сдается, попробует еще раз позже, UI, который предоставляет полезное сообщение об ошибке, веб-приложение, которое представляет экран "ООП", но это восстанавливается приятно... и так далее.

Dave

12
ответ дан Dave Van den Eynde 17 February 2009 в 21:30
поделиться

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

, Когда исключения используются экономно, Вы не должны превращать свой код в выгоду попытки - спагетти, чтобы не получать incomprehensible-in-the-context исключения из более глубоких слоев.

9
ответ дан Joonas Pulakka 17 February 2009 в 21:30
поделиться

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

4
ответ дан RvdK 17 February 2009 в 21:30
поделиться

Как это было уже сказано, используют их для исключительных ситуаций только.

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

public void DoSomethingWithFile() {
    if(!File.Exists(..))
        throw new FileNotFoundException();
}

Предоставляют другой метод пользователю для вызова:

public bool CanDoSomething() {
    return File.Exists(..);
}

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

Также сохраняют Вашу иерархию класса исключений плоской и смотрят на стандартные исключения как InvalidStateException и ArgumentNullExcpetion.

0
ответ дан devdimi 17 February 2009 в 21:30
поделиться

Если Вы выдадите исключения от компонента, то другие разработчики будут использовать в нисходящем направлении, сделайте им большое одолжение и всегда получайте свои собственные классы исключений (при реальной необходимости в них c.f использование стандартных исключений) от станд.:: исключение. Избегайте любой ценой чрезвычайного отвращения как бросок ints, HRESULTS, символ*, станд.:: строка...

0
ответ дан timday 17 February 2009 в 21:30
поделиться

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

В использовании иерархии классов или иерархии классов там несколько вопросов, которые необходимо рассмотреть:

  1. И конструктор копии и деструктор объекта исключения никогда не должны выдавать исключение. Если они делают Вы - программа, сразу завершится. (ISO 15.5/1)

  2. , Если Ваши объекты исключения имеют базовые классы, то используйте общедоступное наследование.
    обработчик А будет только выбран для полученного к базовому классу, если базовый класс будет доступен . (ISO 15.3/3)

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

, Например:

class Ex {
public:
  Ex(int i) 
  : m_i (i)
  {
    if (i > 10) {
      throw "Exception value out of range";
    }
  }

  int m_i;
};


void foo (bool b) {
  if (! b) {
     // 'b' is false this is bad - throw an exception
     throw Ex(20);    // Ooops - throw's a string, not an Ex
  }
}
1
ответ дан Richard Corden 17 February 2009 в 21:30
поделиться

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

  1. ошибки Данных, которые указывают на что-то не так вход. Соответствующие меры должны сохранить сообщение к каталогу журнала, но не обработать его.
  2. ошибки Инфраструктуры, которые указывают на некоторый субкомпонент (как входная очередь, база данных SQL, библиотека JNI) неправильно функционируют. Сон в течение нескольких минут затем снова соединяется.
  3. ошибки Конфигурации, которые указывают на некоторую конфигурацию аспекта, неосуществимы. Выйдите из программы.

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

0
ответ дан Edmund 17 February 2009 в 21:30
поделиться

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

throw NException("Foo::Bar", "Mungulator cause a stack overflow!");

можно затем использовать эти строки в messageboxes и т.д.

, я всегда ловлю через

catch (NException& ex) { ... }

, Если Вы Windows запуска можно передать ошибочное значение и иметь функцию, получают сообщение об ошибке. Лучший пример этого находится в Windows через C/C++ Jeffrey Richter .

1
ответ дан graham.reeds 17 February 2009 в 21:30
поделиться

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

В этой ситуации пользовательский класс является лучшим решением. Я использую этот подход, определяя мои собственные встроенные классы (нет никакого .cpp для них; только.h), например:

class DeviceException {
    ;
}

class DeviceIOException: public DeviceException {
    DeviceIOException(std::string msg, int errorCode);
}

и т.д.

я затем могу судить/реагировать исключение по типу и по информации, содержавшей в.

3
ответ дан Marcin Gil 17 February 2009 в 21:30
поделиться

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

catch(std::exception& e)
блок и делаться с ним. (Хотя часто Вы не будете мочь сойти с рук это, если Вы не будете управлять всем кодом, который может бросить).

я склонен выдавать только исключения, обеспеченные стандарт (т.е. станд.:: runtime_error), но если Вы хотите предоставить дополнительную гранулярность своим обработчикам, необходимо не стесняться получать собственное из станд.:: исключение. См. FAQ C++, облегченный .

кроме того, необходимо бросить временный файл и поймать его ссылкой (для предотвращения копии ctor быть вызванными на сайте выгоды). Бросок указателей также осужден, так как неясно, кто должен очистить память. C++ FAQ, Облегченный соглашения с этим также.

1
ответ дан zdan 17 February 2009 в 21:30
поделиться

Вот простой пример генерации исключения, которое почти не требует ресурсов:

class DivisionError {};
class Division
{
public:
    float Divide(float x, float y) throw(DivisionError)
    {
        float result = 0;
        if(y != 0)
            result = x/y;
        else
            throw DivisionError();
        return result;
    }
};

int main()
{
    Division d;
    try
    {
        d.Divide(10,0);
    }
    catch(DivisionError)
    {
        /*...error handling...*/
    }
}

Выброшенный пустой класс не требует ресурсов или очень мало ...

0
ответ дан 1 December 2019 в 20:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: