11
April

Исключительные ситуации в Java (exceptions and errors)

Posted in: Java technologies, J2SE |

Эта статья посвящается очень важному вопросу программирования - исключительным ситуациям и ошибкам (exceptions and errors).
В языке Java исключения (Exceptions) и ошибки (Errors) являются объектами. Когда метод вызывает (бросает - throws) исключительную ситуацию, он на самом деле работает с объектом. Но такое происходит не с любыми объектами, а только с теми, которые наследуются от Throwable.
Упрощенную диаграмму классов ошибок и исключительний вы можете увидеть на следующем рисунке:

Exceptions and Errors Hierarchy
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.



April 12, 2007 #

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

Я бы сказал не стоит использовать исключения для управления flow алгоритма (типа выхода из вложенного цикла и все такое). А вот для реализации частей бизнес-логики как раз таки иногда и нужно, но только те которые checked. Классический пример - снятие денег со счета, когда выкидывается исключение, говорящее о том что денюшок то не хватает. Вот тут как раз клиенту метода снятия надо реализовать бизнес-логику по обработке такой ситуации.

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

P.S. Ну конечно бывают ситуации исключительные. Но это не более 20%.

klim
April 28, 2007 #

Классический пример - снятие денег со счета, когда выкидывается исключение, говорящее о том что денюшок то не хватает.

Очень дурной стиль так делать.

Entry_N3
April 30, 2007 #

Steve McConnell: “По оценкам некоторых ученых код на целых 90% состоит из блоков обработки исключительных ситуаций, ошибок и т. п., из чего следует, что только 10% кода отвечают за номинальный режим работы программы (Shaw in Bentley, 1982).”

lucker
May 6, 2007 #

Очень дурной стиль так делать.

Хм. это почему? Альтернатива? Я же говорю не об использовании исключений для управление flow программы, а об использовании их для сигнализации того, что запрошенная операция не может быть выполнена с объяснением причины.

January 18, 2008 #

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

смотрите:

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 (снятием денег).

January 18, 2008 #

В предыдущем пример вкрался подлый баг, исправьте пожалуйста, там символ “меньше чем” вставился как тег. И “полетела” часть кода.
Ну и если совсем обнаглеть
А слабо сделать Preview перед отправкой сообщения.

January 18, 2008 #

2 lucker: ну да, я и имел в виду управление ходом выполнения программы. Грубый пример - поймать NPL, сделать заключение, что объект таки да null :), ну и как-то это подправить.
2 black zorro: Весь код пропал куда-то. Исправил на сколько смог понять идею. Если что-то напутал, напиши, пожалуйста.
А на счет preview - я PHP плохо знаю. Разве что найду где-нибудь plugin с функциональностью предварительного просмотра.

January 20, 2008 #

Насчет плагинов для 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

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>