2014-02-12 4 views
11

Я могу проверить вход и если это недопустимый ввод от пользователя, я могу использовать простое условие «если», которое печатает «ввод недействительным, пожалуйста, введите его снова» (в случае наличия недопустимого ввода).Зачем нам нужна обработка исключений?

Этот подход «если есть потенциал для отказа, проверьте его с помощью условия if, а затем укажите правильное поведение при возникновении сбоя ...» для меня достаточно.

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

+3

Проблема заключается в том, что вы не можете покрыть все. – herohuyongtao

+0

Этот вопрос лучше подходит для программистов.stackexchange.com – Incognito

+0

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

ответ

4

Предположим, у вас есть func1, вызывающий func2 с некоторым вводом.

Теперь, предположим, func2 не работает по какой-либо причине.

Ваше предложение - обработать неисправность в пределах func2, а затем вернуться к func1.

Как будет func1 «знать», какая ошибка (если она есть) произошла в func2 и как исходить из этой точки?

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

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

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

Вы все еще можете спорить, конечно, «ну, что же такое try/catch? Почему бы просто не вернуть этот объект?».

К счастью, этот вопрос уже был дан ответ здесь в деталях:

In C++ what are the benefits of using exceptions and try/catch instead of just returning an error code?

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

  1. с исключением, программист должен либо обработать его или бросить его «вверх», в то время как с кодом ошибки, программист может ошибочно игнорировать его.

  2. С механизмом исключения вы можете написать свой код «очиститель» и иметь все, что «автоматически обрабатывается», с кодами ошибок, которые вы обязаны реализовать «утомительный» switch/case, возможно, в каждой функции «вверх по вызову» -stack».

0

Давайте предположим, что вам нужно написать код для какого-либо объекта, который состоит из п различных ресурсов (п> 3), которые будут выделены в конструкторе и высвобождены внутри деструктора. Давайте говорить, что некоторые из этих ресурсов зависят друг от друга. .для создания карты памяти некоторого файла сначала нужно было бы успешно открыть файл, а затем выполнить функцию ОС для сопоставления памяти. Без обработки исключений вы не сможете использовать конструктор (ы) для распределения этих ресурсов, но вы, вероятно, будете использовать двухэтапную инициализацию. Вы должны сами позаботиться о порядке строительства и разрушения - так как вы больше не используете конструктор. Без обработки исключений вы не сможете вернуть богатую информацию об ошибках вызывающему абоненту - вот почему в бесплатном программном обеспечении для исключения обычно требуется отладчик и отлаживаемый исполняемый файл, чтобы определить, почему неожиданно возникает некоторая сложная часть программного обеспечения. Это снова предполагает, что не каждая библиотека может просто сбрасывать информацию об ошибках в stderr. stderr в некоторых случаях недоступен, что, в свою очередь, делает весь код, который использует stderr для сообщения об ошибках, непригодным для использования. Использование C++ Exception Handling вы просто привязывали бы классы, переносящие соответствующие системные вызовы в отношения базового или членского класса И компилятор позаботился о порядке построения и уничтожения и только для вызова деструкторов для неудачных конструкторов.

0

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

public double calculatePercentage(int a, int b) { 
    if (b == 0) { 
     return -1; 
    } 
    else {  
     return 100.0 * (a/b); 
    } 
} 

выше метод использует код возврата -1, чтобы указать отказ (потому что он не может делить на ноль). Это будет работать, но ваш код вызова должен знать об этой конвенции, например, это может произойти:

public double addPercentages(int a, int b, int c, int d) { 
    double percentage1 = calculatePercentage(a, b); 
    double percentage2 = calculatePercentage(c, c); 
    return percentage1 + percentage2; 
} 

Приведенный выше код выглядит хорошо на первый взгляд. Но когда b или d равны нулю, результат будет неожиданным. calculatePercentage вернет -1 и добавит его к другому проценту, который, скорее всего, неверен. Программист, который написал addPercentages, не знает, что в этом коде есть ошибка, пока он не проверит его, и даже тогда, только если здесь действительно проверяется достоверность результатов.

С исключениями вы можете сделать это:

public double calculatePercentage(int a, int b) { 
    if (b == 0) { 
     throw new IllegalArgumentException("Second argument cannot be zero"); 
    } 
    else {  
     return 100.0 * (a/b); 
    } 
} 

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

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

public double calculatePercentage(int a, int b) throws MyCalculationException { 
    if (b == 0) { 
     throw new MyCalculationException("Second argument cannot be zero"); 
    } 
    else {  
     return 100.0 * (a/b); 
    } 
} 

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

Разработчики Java в настоящее время, как правило, согласны с тем, что проверенные исключения являются слишком инвазивными, поэтому большинство API в последнее время тяготеют к неконтролируемым исключениям.

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

общественного класса MyCalculationException расширяет Exception {

public MyCalculationException(String message) { 
     super(message); 
    } 

}

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

(см Throwable class hierarchy)

Смежные вопросы