Могу ли я использовать исключения в качестве инструментов, чтобы "поймать" и ошибок рано?

Я использую исключения, чтобы поймать проблемы на ранней стадии. Например:

public int getAverageAge(Person p1, Person p2){
    if(p1 == null || p2 == null)
        throw new IllegalArgumentException("One or more of input persons is null").
    return (p1.getAge() + p2.getAge()) / 2;
}

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

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

Теперь вы'вновь в порядке, в этом случае равен null будет просто исключение NullPointerException сразу, поэтому он не может быть лучшим примером.

Но рассмотрим такой метод, как этот, например:

public void registerPerson(Person person){
    persons.add(person);
    notifyRegisterObservers(person); // sends the person object to all kinds of objects.
}

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

Изменения функции вот так:

public void registerPerson(Person person){
    if(person == null) throw new IllegalArgumentException("Input person is null.");
    persons.add(person);
    notifyRegisterObservers(person); // sends the person object to all kinds of objects.
}

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

Кроме того, "нулевой" ссылки в качестве параметра-это только пример. Это может быть много проблем, от недопустимых аргументов к что-нибудь еще. Это's всегда лучше обнаружить их раньше.


Так что мой вопрос прост: является ли это хорошей практикой? Мое использование исключений как проблему-предотвращение хороших инструментов? Является ли это законным применение исключений или это проблематично?

Комментарии к вопросу (12)
Решение

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

Комментарии (2)

Да, исключений является хорошей идеей. Выбросить их раньше, бросают их чаще, бросают их с нетерпением.

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

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

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

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

public class PersonArgumentException extends IllegalArgumentException {
    public MyException(String message) {
        super(message);
    }
}

Затем, когда кто-то видит PersonArgumentException, это'ы понятно, где это'ы откуда. Там'ы балансирование о том, сколько пользовательских исключений, которые вы хотите добавить, потому что вы Don'т хотим, чтобы плодить сущности без надобности (Оккам'ы бритвы). Чаще всего несколько пользовательских исключений достаточно, чтобы сигнал на "этот модуль разве'т получить право данных!" или "этот модуль может'т делать, что это'ы делать!" в пути, который является конкретной и целевой, но не так-точны, что вы должны повторно реализовать всю иерархию исключений. Я часто прихожу к тому, что небольшой набор пользовательских исключений, начиная с фондовой исключения, затем сканировать код и поняв, что "эти N мест содержания скота и исключения, но они упирают на более высоком уровне идея о том, что они'повторно не получать данные, которые им нужны; пусть'ы заменить шток исключения с более высокого уровня, исключение, которое более ясно говорит о том, что'ы происходит на самом деле.&и"

Комментарии (5)

Как можно скорее, не при отладке приложения. Я помню сегментации в наследство на C++ программы : Место, в котором ошибка была обнаружена не имел ничего общего с тем местом, где он был введен (нулевой указатель был благополучно перемещен с одного места на другое в памяти, прежде чем он, наконец, вызвало проблемы). Трассировки стека не может помочь вам в тех случаях.

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

В вашем конкретном случае, например, если ссылка имеет значение null, исключение NullReferenceException будут брошены на следующем утверждении, когда пытаешься сделать им возраста одного человека. Вы Don't действительно нужно проверить все сами здесь: let базовой системой поймать эти ошибки и исключения, что's, почему они exist.

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

  1. Короче писать и читать:

утверждать Р1 : "по-Р1 имеет значение null тогда"; утверждать, Р2 : "по Р2-нуль" - а;

  1. Специально разработаны для вашего подхода. В мире, где у вас есть оба утверждения и исключения, их можно отличить следующим образом:
  • Заявления за ошибки программирования (" ПО - / это не должно повториться /с"),
  • Исключения для случаях, (исключительных, но вероятных ситуаций)

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

Статический анализатор (например, компилятор) может быть счастливее тоже.

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

Комментарии (0)

Насколько я знаю, разные программисты предпочитают одно решение или другое.

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

Я нахожу второе решение, например

public void registerPerson(Person person){
    if(person == null) throw new IllegalArgumentException("Input person is null.");
    persons.add(person);
    notifyRegisterObservers(person); // sends the person object to all kinds of objects.
}

более твердым, потому что

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

Поэтому, особенно если код достаточно сложный, я предпочитаю второй подход.

Комментарии (1)

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

Но давайте рассмотрим немного другой пример.

class PersonCalculator {
    PersonCalculator(Person p) {
        if (p == null) throw new ArgumentNullException("p");
        _p = p;
    }

    void Calculate() {
        // Do something to p
    }
}

Если нет проверки аргумента в конструктор, вы получите `исключение NullReferenceException при вызове "рассчитать".

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

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

Комментарии (0)

Не в пример вам дать.

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

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

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

Комментарии (0)

В вашем примере функция, я бы предпочел, чтобы ты не проверяй, а просто позвольте исключение NullReferenceException случиться.

Например, нет смысла быть в любом случае проходящий там нуль, поэтому я'МР понять, проблема сразу же на основе метание исключение NullReferenceException.

Два, это то, что если каждая функция бросает несколько разных исключений, основываясь на том, что какая-то явно неправильная материалы, то очень скоро вы've получили функции, которая может создавать 18 различных типов исключений, и очень скоро вы окажетесь говоря, что's слишком много работы, чтобы заниматься, а просто подавляя все исключения в любом случае.

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

Комментарии (5)