Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Используйте исключения лишь в исключительных ситуациях



 

Однажды, если вам не повезет, вы сделаете ошибку в программе, например, такую:

// Неправильное использование исключений. Никогда так не делайте!

try {

int i = 0;

while(true)

а[i++]. f();

} catch(ArraylndexOutOfBoundsException е) {  }

 

Что делает этот код? Изучение кода не вносит полной ясности, и это достаточная причина, чтобы им не пользоваться. Здесь приведена плохо продуманная идиома для циклического перебора элементов в массиве. Когда производится попытка обращения к первому элементу за пределами массива, бесконечный цикл завершается иниции­рованием исключительной ситуации ArraylndexOutOfBoundException, ее перехватом и последующим игнорированием. Предполагается, что это эквивалентно стандартной идиоме цикла по массиву, которую узнает любой программист java:

for (int i = 0; i < a.length; i++)

a[i].f();

 

158

 

Но почему же кто-то выбрал идиому, использующую исключения, вместо другой, испытанной и правильной? Это вводящая в заблуждение попытка улучшить произво­дительность, которая исходит из ложного умозаключения, что, поскольку виртуальная машина проверяет границы при всех обращениях к массиву, обычная проверка на завершение цикла (i < a.length) избыточна и ее следует устранить. В этом рассуж­дении неверны три момента:

 

· Так как исключения создавались для применения в исключительных условиях, лишь очень немногие реализации JVM пытаются их оптимизировать (если таковые есть вообще). Обычно создание, инициирование и перехват исключения дорого обходится системе

 

· Размещение кода внутри блока try-catch препятствует выполнению определенных процедур оптимизации, которые в противном случае могли бы быть исполнены в современных реализациях jVM.

 

· Стандартная идиома цикла по массиву вовсе не обязательно приводит к выполнению избыточных проверок, в процессе оптимизации некоторые современные реализации jVM отбрасывают их.

Практически во всех современных реализациях jVM идиома, использующая ис­ключения, работает гораздо медленнее стандартной идиомы. На моей машине идиома, использующая исключения, выполняет цикл от 0 до 99 в семьдесят раз медленней стандартной.

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

Мораль проста: исключения, как и подразумевает их название, должны при­меняться лишь для исключительных ситуаций, при обычной обработке исполь­зовать их не следует никогда. Вообще говоря, вы всегда должны предпочитать стандартные, легко распознаваемые идиомы идиомам с ухищрениями, предлагающим лучшую производительность. Даже если имеет место реальный выигрыш в производи­тельности, он может быть поглощен неуклонным совершенствованием реализаций jVM. А вот коварные ошибки и сложность поддержки, вызываемые чересчур хитро­умными идиомами, наверняка останутся.

 

159

 

 

Этот принцип относится также к проектированию АРI. Хорошо спроектиро­ванный API не должен заставлять своих клиентов использовать исключения для обычного управления потоком вычислений. Если в классе есть метод, зависящий от состояния (state-dependent), который может быть вызван лишь при выполнении определенных непредсказуемых условий, то в этом же классе, как правило, должен присутствовать отдельный метод, проверяющий состояние (state-testing), который по­казывает, можно ли вызывать первый метод. Например, класс Iterator имеет завися­щий от состояния метод next, который возвращает элемент для следующего прохода цикла, а также соответствующий метод проверки состояния hasNext. Это позволяет применять для просмотра коллекции в цикле следующую стандартную идиому:

for (Iterator i = collection. iterator(); i. hasNext(); ) {

 Foo foo = (Foo) i.next(); }

 

Если бы в классе Iterator не было бы метода hasNext, клиент был бы вынужден использовать следующую конструкцию:

 // Не пользуйтесь этой отвратительной идиомой

 // для просмотра коллекции в цикле!

 

try {

Iterator i = collection.iterator();

 while(true) {

Foo foo = (Foo) i.next();

}

} catch (NoSuchElementException е) { }

 

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

В качестве альтернативы отдельному методу про верки состояния можно исполь­зовать особый зависящий от состояния метод: он будет возвращать особое значение, например null, при вызове для объекта, имеющего неподходящее состояние. Для класса Iterator этот прием не годится, поскольку null является допустимым значени­ем для метода next.

Приведем некоторые рекомендации, которые помогут вам сделать выбор между методом проверки состояния и особым возвращаемым значением. Если к объекту возможен одновременный доступ без внешней синхронизации или если смена его СОСТОJШИЙ инициируется извне, может потребоваться прием с особым возвращаемым

 

 

160

 

 

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

 


Поделиться:



Последнее изменение этой страницы: 2019-04-11; Просмотров: 227; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.014 с.)
Главная | Случайная страница | Обратная связь