Рейтинговые книги
Читем онлайн Философия Java3 - Брюс Эккель

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 61 62 63 64 65 66 67 68 69 ... 132

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

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

Основные исключения

Исключительной ситуацией называется проблема, из-за которой нормальное продолжение работы метода или части программы, выполняющихся в данный момент, становится невозможным. Важно отличать исключительную ситуацию от «обычных» ошибок, когда в текущем контексте имеется достаточно информации для преодоления затруднений. В исключительной ситуации обработать исключение в текущем контексте невозможно, потому что вы не располагаете необходимой информацией. Остается единственный выход — покинуть текущий контекст и передать проблему на более высокий уровень. Именно это и происходит при выдаче исключения.

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

При возбуждении исключения происходит сразу несколько вещей. Во-пер-вых, создается объект, представляющий исключение, — точно так же, как и любой другой объект в Java (в куче, оператором new). Далее текущий поток исполнения (тот самый, где произошла ошибка) останавливается, и ссылка на объект, представляющий исключение, извлекается из текущего контекста. С этого момента включается механизм обработки исключений, который начинает поиск подходящего места программы для передачи исключения. Таким местом является обработчик исключений, который пытается решить возникшую проблему так, чтобы программа могла снова попытаться выполнить проблемную операцию или просто продолжила свое выполнение.

В качестве простого примера выдачи исключения представьте ссылку на объект t. Возможно, полученная вами ссылка не была инициализирована; стоит проверить это обстоятельство, прежде чем вызывать методы с использованием этой ссылки. Чтобы передать информацию об ошибке на более высокий уровень, создайте объект, представляющий передаваемую информацию, и «запустите» его из текущего контекста. Тем самым вы возбудите исключение. Вот как это выглядит:

if(t — null)

throw new NullPointerException( );

Вырабатывается исключение, которое позволяет вам — в текущем контексте — переложить с себя ответственность, не задумываясь о будущем. Ошибка, словно по волшебству, обрабатывается где-то в другом месте (вскоре мы узнаем, где именно).

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

Аргументы исключения

Исключения, как и любые объекты Java, создаются в куче оператором new, который выделяет память и вызывает конструктор. У всех стандартных исключений существует два конструктора: стандартный (по умолчанию) и другой, со строковым аргументом, в котором можно разместить подходящую информацию об исключении:

throw new NullPointerExceptionC't = null");

Переданная строка потом может быть извлечена различными способами, о чем будет рассказано позже.

Ключевое слово throw влечет за собой ряд довольно интересных действий. Как правило, сначала new используется для создания объекта, представляющего условие происшедшей ошибки. Ссылка на указанный объект передается команде throw. Фактически этот объект «возвращается» методом, несмотря на то что для возвращаемого объекта обычно предусмотрен совсем другой тип. Таким образом, упрощенно можно говорить об обработке исключений как об альтернативном механизме возврата из исполняемого метода (впрочем, с этой аналогией не стоит заходить слишком далеко). Возбуждение исключений также позволяет выходить из простых блоков видимости. В обоих случаях возвращается объект исключения и происходит выход из текущего метода или блока.

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

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

Перехват исключений

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

Блок try

Если вы «находитесь» внутри метода и инициируете исключение (или это делает другой вызванный метод), этот метод завершит работу при возникновении исключения. Но если вы не хотите, чтобы оператор throw завершил работу метода, разместите в методе специальный блок для перехвата исключения — так называемый блок try. Этот блок представляет собой простую область действия, которой предшествует ключевое слово try:

try {

// Фрагмент, способный возбуждать исключения

}

Если бы не обработка исключений, для тщательной проверки ошибок вам пришлось бы добавить к вызову каждого метода дополнительный код для проверки ошибок — даже при многократном вызове одного метода. С обработкой исключений весь код размещается в блоке try, который и перехватывает все возможные исключения в одном месте. А это означает, что вашу программу становится значительно легче писать и читать, поскольку выполняемая задача не смешивается с обработкой ошибок.

Обработчики исключений

Конечно, возбужденное исключение в конечном итоге должно быть где-то обработано. Этим местом является обработчик исключений, который создается для каждого исключения, которое вы хотите перехватить. Обработчики исключений размещаются прямо за блоком try и обозначаются ключевым словом catch:

try {

// Часть программы, способная возбуждать исключения } catch(Typel idl) {

// Обработка исключения Typel } catch(Туре2 id2) {

// Обработка исключения Туре2 } catch(ТуреЗ id3) {

// Обработка исключения ТуреЗ

}

//ИТ д.

Каждое предложение catch (обработчик исключения) напоминает маленький метод, принимающий один и только один аргумент определенного типа. Идентификатор (idl, id2 и т. д.) может использоваться внутри обработчика точно так же, как и метод распоряжается своими аргументами. Иногда этот идентификатор остается невостребованным, так как тип исключения дает достаточно информации для его обработки, но тем не менее присутствует он всегда.

Обработчики всегда следуют прямо за блоком try. При возникновении исключения механизм обработки исключений ищет первый из обработчиков исключений, аргумент которого соответствует текущему типу исключения. После этого он передает управление в блок catch, и таким образом исключение считается обработанным. После выполнения предложения catch поиск обработчиков исключения прекращается. Выполняется только одна секция catch, соответствующая типу исключения; в этом отношении обработка исключений отличается от команды switch, где нужно дописывать break после каждого case, чтобы предотвратить исполнение всех прочих case.

1 ... 61 62 63 64 65 66 67 68 69 ... 132
На этой странице вы можете бесплатно читать книгу Философия Java3 - Брюс Эккель бесплатно.
Похожие на Философия Java3 - Брюс Эккель книги

Оставить комментарий