April
Эта статья посвящается очень важному вопросу программирования - исключительным ситуациям и ошибкам (exceptions and errors).
В языке Java исключения (Exceptions) и ошибки (Errors) являются объектами. Когда метод вызывает (бросает - throws) исключительную ситуацию, он на самом деле работает с объектом. Но такое происходит не с любыми объектами, а только с теми, которые наследуются от Throwable.
Упрощенную диаграмму классов ошибок и исключительний вы можете увидеть на следующем рисунке:
RuntimeException, Error и их наследников еще называют unchecked exception, а всех остальных наследников класса Exception - checked exception. Checked Exception обязывает пользователя обработать ее (использую конструкцию try-catch) или же отдать на откуп обрамляющим методам (в таком случае к декларации метода дописывают конструкцию throws).
1. Так когда же нужно бросать ошибки?. На этот вопрос можно ответить просто: если в методе возможна ситуация, которую метод не в состоянии обработать самостоятельно, он должен “бросать” ошибку.
Но ни в коем случае нельзя использовать исключительные ситуации для реализации частей бизнесс-логики.
Чаще всего Exceptions бросаются при нарушении контракта метода. Контракт (contract) - это негласное соглашение между создателем метода (метод сделает и/или вернет именно то, что надо) и пользователем метода (на вход метода будут передаваться значения из множества допустимых).
Нарушение контракта со стороны создателя метода - это, например, что-нибудь на подобии MethodNotImplementedYetException :).
Пользователь метода может нарушить контракт, например, таким способом: на вход Integer.parseInt(String) подать строку с буквами и по заслугам получить NumberFormatException.
2. А что собственно бросать?. Выбор не то чтобы сильно велик, но и не однозначен: checked, unchecked (runtime), unchecked (error).
Сразу скажу, в подавляющем большинстве случаев Error вам не понадобится. Это в основном критические ошибки (например, StackOverflowError), с которыми пусть работает JVM.
Checked Exceptions, как было написано выше, заставляет программиста-пользователя написать код для ее обработки или же описать метод как “вызывающий исключительную ситуацию”.
С unchecked exception можно поступить по-разному. В случае с такими ошибками, пользователь сам решает, будет он обрабатывать эту ошибку, или же нет (компилятор не заставляет это делать).
Можно написать следующее простое правило: если некоторый набор входящих в метод данных может привести к нарушению контракта, и вы считаете, что программисту-пользователю важно разобраться с этим, описывайте метод с конструкцией throws, иначе бросайте unchecked exception.
3. Зачем нужно все это делать? А почему бы и нет :). Если серьезно - правильное использование Exceptions и корректная их обработка сделают код более понятным, гибким, структурированным и возможным для повторного использования.
Жду ваших вопросов и комментариев.
8 Comments »
RSS feed for comments on this post.
Но ни в коем случае нельзя использовать исключительные ситуации для реализации частей бизнесс-логики.
Я бы сказал не стоит использовать исключения для управления flow алгоритма (типа выхода из вложенного цикла и все такое). А вот для реализации частей бизнес-логики как раз таки иногда и нужно, но только те которые checked. Классический пример - снятие денег со счета, когда выкидывается исключение, говорящее о том что денюшок то не хватает. Вот тут как раз клиенту метода снятия надо реализовать бизнес-логику по обработке такой ситуации.
Ну а в тех случаях когда речь идет о нарушении контракта метода (не бизнес-ограничений) не надо и задумываться - только unchecked, и ловить их должен код, находящийся в самом начале потока, и ничего кроме логирования информации об ошибки с ними сделать он не может, да и не должен.
P.S. Ну конечно бывают ситуации исключительные. Но это не более 20%.
Классический пример - снятие денег со счета, когда выкидывается исключение, говорящее о том что денюшок то не хватает.
Очень дурной стиль так делать.
Steve McConnell: “По оценкам некоторых ученых код на целых 90% состоит из блоков обработки исключительных ситуаций, ошибок и т. п., из чего следует, что только 10% кода отвечают за номинальный режим работы программы (Shaw in Bentley, 1982).”
Очень дурной стиль так делать.
Хм. это почему? Альтернатива? Я же говорю не об использовании исключений для управление flow программы, а об использовании их для сигнализации того, что запрошенная операция не может быть выполнена с объяснением причины.
Я бы не сказал, что использовать исключительные ситуации для реализации логики - это плохо.
смотрите:
class Banka {
private double _bablo;
public double getBablo (){return _bablo;}
public void foo (int a) {
if (_bablo < a)
b.foo (_bablo);
else
_bablo -= a;
}
}
использование в вариенте 1.
Banka b = new Banka ();
double sum = 0;
double bablo = b.getBablo();
b.foo (100);
if (bablo <= 100)
sum += 100;
else
sum += bablo;
второй вариант:
class Banka {
private double _bablo;
public double getBablo (){return _bablo;}
public void foo (int a) {
if (_bablo < a)
throw new NoBablo();
_bablo -= a;
}
}
использование в вариенте 2.
Banka b = new Banka ();
try{
b.foo (100);
}
catch (NoBablo e){
// no bablo
}
Кажется, что разницы между первым подходом и вторым нет. И там и там есть контроль над снятием денег. Но в первом случае мы размазываем логику работы банка во множестве мест.
А теперь представим ситуацию, что правило снятия бабла поменялось (хотя на стадии проектирования аналитик клялся, что никогда и нигде такого быть не может, но мы все знаем цену их обещаниям) и теперь можно снимать бабло на сумму большую чем есть на счете. Соотвественно, правим метод (это легко), а потом пошли искать в тысяче мест где возможно мы вставили проверку перед вызовом foo (снятием денег).
В предыдущем пример вкрался подлый баг, исправьте пожалуйста, там символ “меньше чем” вставился как тег. И “полетела” часть кода.
Ну и если совсем обнаглеть
А слабо сделать Preview перед отправкой сообщения.
2 lucker: ну да, я и имел в виду управление ходом выполнения программы. Грубый пример - поймать NPL, сделать заключение, что объект таки да null :), ну и как-то это подправить.
2 black zorro: Весь код пропал куда-то. Исправил на сколько смог понять идею. Если что-то напутал, напиши, пожалуйста.
А на счет preview - я PHP плохо знаю. Разве что найду где-нибудь plugin с функциональностью предварительного просмотра.
Насчет плагинов для wordpress.
Сразу предупредив, что с wordpress знаком шапочно (собственный сайт на mediawiki).
По следующей ссылке Вы можете найти каталог с плагинами расширяющими функции комментирования:
http://blog.trampampam.ru/wordpress/comments_plugins/
Чтобы не играть роль google решил поставить парочку из них и посмотреть функциональность.
http://wordpress.org/extend/plugins/live-comment-preview/
http://blogwaffe.com/ajax-comment-preview/ - установился без проблем, внизу после формы добавления комментария появилась кнопка “Preview”. Хотя зачем нужна эта кнопка я не понял, т.к. при наборе текста сразу после text-области появляется предпросмотр. Впечатления положительные, т.к. попытка ввести текст с символами “меньше чем” и “больше чем” была отловлена.
Посоветую еще поставить http://sw-guide.de/wordpress/plugins/edit-comments-xt/. Добавляется функция редактирования своего комментария в течении некоторого времени после отправки. Из минусов: редактирование только для зарегистрированных пользователей.
Подсветка: в коментариях может встречаться пример исходников и их было бы тоже очень неплохо подсветить. Я пользуюсь библиотечкой от “softwaremaniac-а”,
но еще рекомендуют codecolorer (никогда не сталкивался, но учитывая что он построен на базе geshi все должно быть “колечком”).
http://www.tretyak.com/2007/05/08/syntax-highlighters-for-wordpress.html
Исправленный пример кода - http://paste.bradleygill.com/index.php?paste_id=185