Главная » Java, Советы » Применяйте обрабатываемые исключения для восстановления, для программных ошибок используйте исключения времени выполнения

0

 

в языке программирования Java предусмотрены три типа объектов Throwable: обрабатываемые исключения (checked exception), исключения времени выполнения (rиn-time exception) и ошибки (error). Программисты обычно путают, при каких условиях следует использовать каждый из этих типов. Решение не всегда очевидно, но есть несколько общих правил, в значительной мере упрощающих выбор.

Основное правило при выборе между обрабатываемым и необрабатываемым исключениями гласит: используйте обрабатываемые исключения для тех условий, когда есть основания полагать, что инициатор вызова способен их обработать. Генерируя обрабатываемое исключение, вы принуждаете инициатора вызова обрабатывать его в операторе catch или передавать дальше. Каждое обрабатываемое исключение, которое, согласно декларации, инициирует некий метод, является, таким образом, серьезным предупреждением для пользователя АРI о том, что при вызове данного метода могут возникнуть соответствующие условия.

Предоставляя пользователю АР! обрабатываемое исключение, разработчик АР! передает ему право осуществлять обработку соответствующего условия. Пользователь может пренебречь этим правом, перехватив исключение и проигнорировав его. Однако, как правило, это оказывается плохим решением (статья 47).

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

Используйте исключения времени выполнении для индикации программных ошибок. Подавляющее большинство исключений времени выполнения сообщает о нарушении предусловий (precondition violation). Нарушение предусловия означает

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

Хотя в спецификации языка Java это не оговорено, существует строго соблюдаемое соглашение о том, что ошибки зарезервированы в JVM для того, чтобы фиксировать дефицит ресурсов, нарушение инвариантов и другие условия, делающие невозможным дальнейшее выполнение программы [Chan98, HorstmanOO]. Поскольку эти соглашения признаны практически повсеместно, лучше для Error вообще не создавать новых подклассов. Все реализуемые вами необрабатываемые исключения должны прямо или косвенно наследовать класс RuntimeException.

Для исключительной ситуации можно определить класс, который не наследует классов Exception, RuntimeException и Error. В спецификации· языка Java такие классы напрямую не оговариваются, однако неявно подразумевается, что они будут вести себя так же, как обычные обрабатываемые исключения (которые являются подклассами класса Exception, но не RuntimeException). Когда же вы должны использовать этот класс? Если одним словом, то никогда. Не имея никаких преимуществ перед обычным обрабатываемым исключением, он будет запутывать пользователей вашего API.

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

Разработчики API часто забывают, что исключения – это вполне законченные объекты, для КОТОРЫХ можно определять любые методы. Основное назначение таких методов – создание кода, который увязывал бы исключение с дополнительной информацией об условии, вызвавшем появление данной исключительной ситуации. Если таких методов нет, программистам придется разбираться со строковым представлением этого исключения, выуживая из него дополнительную информацию. Эта крайне плохая практика. Классы редко указывают какие-либо детали в своем строковом представлении, само строковое представление может меняться от реализации к реализации, от версии к версии. Следовательно, программный код, который анализирует строковое представление исключения, скорее всего окажется непереносимым и ненадежным.

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

 

Источник: Джошуа Блох, Java TM Эффективное программирование, Издательство «Лори»

По теме:

  • Комментарии