Spec-Zone .ru
спецификации, руководства, описания, API
Содержание | Предыдущий | Следующий | Индекс Спецификация языка Java
Третий Выпуск


ГЛАВА 11

Исключения


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

Программы могут также выдать исключения явно, используя throw операторы (§14.18).

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

Каждое исключение представляется экземпляром класса Throwable или один из его подклассов; такой объект может использоваться, чтобы перенести информацию от точки, в которой исключение происходит с обработчиком, который ловит это. Обработчики устанавливаются catch пункты try операторы (§14.20). Во время процесса выдачи исключения виртуальная машина Java резко завершает, один за другим, любые выражения, операторы, метод и вызовы конструктора, инициализаторы, и полевые выражения инициализации, которые начали, но не завершили выполнение в текущем потоке. Этот процесс продолжается, пока обработчик не находится, который указывает, что это обрабатывает то определенное исключение, называя класс исключения или суперкласс класса исключения. Если никакой такой обработчик не находится, то метод uncaught-Exception вызывается для ThreadGroup это - родитель текущего потока таким образом, каждое усилие прилагается, чтобы избежать позволять исключению идти необработанное.

Механизм исключения платформы Java интегрируется с ее моделью синхронизации (§17), так, чтобы блокировки были выпущены как synchronized операторы (§14.19) и вызовы synchronized методы (§8.4.3.6, §15.12) завершаются резко.

Эта глава описывает различные причины исключений (§11.1). Это детализирует, как исключения проверяются во время компиляции (§11.2) и обрабатываются во время выполнения (§11.3). Подробному примеру (§11.4) тогда следует объяснение иерархии исключения (§11.5).

11.1 Причины Исключений

Исключение выдается по одной из трех причин:

Исключения представляются экземплярами класса Throwable и экземпляры его подклассов. Эти классы являются, все вместе, классами исключений.

11.2 Время компиляции Проверяя Исключений

Компилятор для языка программирования Java проверяет, во время компиляции, что программа содержит обработчики для проверенных исключений, анализируя, который проверял, что исключения могут следовать из выполнения метода или конструктора. Для каждого проверенного исключения, которое является возможным результатом, throws пункт для метода (§8.4.6) или конструктор (§8.8.5) должен упомянуть класс того исключения или один из суперклассов класса того исключения. Это время компиляции, проверяя на присутствие обработчиков исключений разрабатывается, чтобы сократить количество исключений, которые должным образом не обрабатываются.

Классы исключений непроверенные являются классом RuntimeException и его подклассы, и класс Error и его подклассы. Все другие классы исключений являются проверенными классами исключений. API Java определяет много классов исключений, оба проверенные и непроверенные. Дополнительные классы исключений, оба проверенные и непроверенные, могут быть объявлены программистами. См. §11.5 для описания иерархии класса исключений и некоторые из классов исключений, определенных API Java и виртуальной машиной Java.

Проверенные классы исключений, названные в throws пункт является частью контракта между конструктором и пользователем метода или конструктором. throws пункт метода переопределения, возможно, не определяет, что этот метод приведет к выдаче любого проверенного исключения, которое переопределенный метод не разрешается throws пункт, чтобы бросить. Когда интерфейсы включаются, больше чем одно объявление метода может быть переопределено единственным объявлением переопределения. В этом случае у объявления переопределения должен быть a throws пункт, который является совместимым со всеми переопределенными объявлениями (§9.4).

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

11.2.1 Анализ исключения Выражений

Выражение вызова метода может бросить эквивалентность типа E исключения также:

Выражение создания экземпляра класса может бросить эквивалентность типа E исключения также:

Для любого вида выражения выражение может бросить эквивалентность типа E, одно из ее непосредственных подвыражений может бросить E.

11.2.2 Анализ исключения Операторов

Оператор броска может бросить эквивалентность типа E исключения, статический тип выражения броска является E или подтипом E, или брошенное выражение может бросить E.

Явный оператор вызова конструктора может бросить эквивалентность типа E исключения также:

A try оператор может бросить эквивалентность типа E исключения также:

Любой другой оператор S может бросить эквивалентность типа E исключения, выражение или оператор, сразу содержавшийся в S, могут бросить E.

11.2.3 Проверка исключения

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

Это - ошибка времени компиляции, если статический инициализатор (§8.7) или инициализатор переменной класса в пределах именованного класса или интерфейса §8.3.2, может бросить проверенный тип исключения.

Это - ошибка времени компиляции, если инициализатор переменной экземпляра именованного класса может выдать проверенное исключение, если то исключение или один из его супертипов явно не объявляются в пункте бросков каждого конструктора его класса, и у класса есть по крайней мере один явно объявленный конструктор. Инициализатор переменной экземпляра в анонимном классе (§15.9.5) может выдать любые исключения.

Это - ошибка времени компиляции если a catch выгоды пункта проверенный тип E1 исключения, но там не существует никакой проверенный тип E2 исключения так, что все следующее, содержат:

если E1 не является классом Exception.

11.2.4 Почему Ошибки Не Проверяются

Те классы исключений непроверенные, которые являются ошибочными классами (Error и его подклассы), освобождаются со времени компиляции, проверяя, потому что они могут произойти во многих точках в программе, и восстановление от них является трудным или невозможным. Программа, объявляя такие исключения была бы нарушена, бессмысленно.

11.2.5 Почему Исключения на этапе выполнения Не Проверяются

Классы исключения на этапе выполнения (RuntimeException и его подклассы), освобождаются со времени компиляции, проверяя, потому что, в суждении разработчиков языка программирования Java, имея необходимость объявить такие исключения не помог бы значительно в установлении правильности программ. Многие из операций и конструкции языка программирования Java могут привести к исключениям на этапе выполнения. Информация, доступная компилятору, и уровню анализа, который выполняет компилятор, обычно не достаточна, чтобы установить, что такие исключения на этапе выполнения не могут произойти, даже при том, что это может быть очевидно для программиста. Требование, чтобы такие классы исключений были объявлены, просто было бы раздражением программистам.

Например, определенный код мог бы реализовать круговую структуру данных, которая, конструкцией, никогда не может включать null ссылки; программист может тогда быть уверенным это a NullPointerException не может произойти, но для компилятора было бы трудно доказать это. Технология доказательства теорем, которая необходима, чтобы установить такие глобальные свойства структур данных, выходит за рамки этой спецификации.

11.3 Обработка Исключения

Когда исключение выдается, управление передается от кода, который вызвал исключение к самому близкому динамически включающему catch пункт a try оператор (§14.20), который обрабатывает исключение.

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

Вызывающая сторона оператора или выражения зависит от того, где это происходит:

Ли деталь catch дескрипторы пункта исключение определяется, сравнивая класс объекта, который был брошен в объявленный тип параметра catch пункт. catch пункт обрабатывает исключение, если тип его параметра является классом исключения или суперклассом класса исключения. Эквивалентно, a catch пункт поймает любой объект исключения, который является instanceof (§15.20.2) объявленный тип параметра.

Передача управления, которая происходит, когда исключение выдается причины резкое завершение выражений (§15.6) и операторы (§14.1) до a catch с пунктом встречаются, который может обработать исключение; выполнение тогда продолжается, выполняя блок этого catch пункт. Код, который вызвал исключение, никогда не возобновляется.

Если нет catch пункт, обрабатывающий исключение, может быть найден, тогда текущий поток (поток, который встречался, исключение) завершается, но только в конце концов finally пункты были выполнены и метод uncaughtException был вызван для ThreadGroup это - родитель текущего потока.

В ситуациях, где это является требуемым, чтобы гарантировать, что один блок кода всегда выполняется за другим, даже если тот другой блок кода завершается резко, a try оператор с a finally пункт (§14.20.2) может использоваться.

Если a try или catch блок в a try-finally или try-catch-finally оператор завершается резко, тогда finally пункт выполняется во время распространения исключения, даже если никакое соответствие catch пункт в конечном счете находится. Если a finally пункт выполняется из-за резкого завершения a try блок и finally сам пункт завершается резко, тогда причина резкого завершения try блок отбрасывается, и новая причина резкого завершения распространяется оттуда.

Точные правила для резкого завершения и для ловли исключений определяются подробно со спецификацией каждого оператора в §14 и для выражений в §15 (особенно §15.6).

11.3.1 Исключения Точны

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

11.3.2 Обработка Асинхронных Исключений

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

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

Асинхронные исключения редки. Они происходят только в результате:

stop методы могут быть вызваны одним потоком, чтобы влиять на другой поток или все потоки в указанной группе потока. Они являются асинхронными, потому что они могут произойти в любой точке в выполнении другого потока или потоков. InternalError считается асинхронным.

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

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

Бумага, Опрашивающая Эффективно на Аппаратных средствах Запаса Марком Фили, Proc. Конференция 1993 года по Функциональному программированию и Архитектуре ЭВМ, Копенгагену, Дания, стр 179-187, рекомендуется как дальнейшее чтение.

Как все исключения, асинхронные исключения точны (§11.3.1).

11.4 Пример Исключений

Рассмотрите следующий пример:

class TestException extends Exception {
	TestException() { super(); }
	TestException(String s) { super(s); }
}
class Test {
	public static void main(String[] args) {
		for (String arg :args) {
			try {
				thrower(arg);
				System.out.println("Test \"" + arg +
					"\" didn't throw an exception");
			} catch (Exception e) {
				System.out.println("Test \"" + arg +
					"\" threw a " + e.getClass() +
					"\n        with message: " + e.getMessage());
			}
		}
	}
	static int thrower(String s) throws TestException {
		try {
			if (s.equals("divide")) {
				int i = 0;
				return i/i;
			}
			if (s.equals("null")) {
				s = null;
				return s.length();
			}
			if (s.equals("test"))
				throw new TestException("Test message");
			return 0;
		} finally {
			System.out.println("[thrower(\"" + s +
					"\") done]");
		}
	}
}
Если мы выполняем тестовую программу, передавая это параметры:

divide null not test
это производит вывод:

[thrower("divide") done]
Test "divide" threw a class java.lang.ArithmeticException
        with message: / by zero
[thrower("null") done]
Test "null" threw a class java.lang.NullPointerException
        with message: null
[thrower("not") done]
Test "not" didn't throw an exception
[thrower("test") done]
Test "test" threw a class TestException
        with message: Test message

Этот пример объявляет класс исключений TestException. main метод класса Test вызывает thrower метод четыре раза, заставляя исключения быть брошенным три из этих четырех раз. try оператор в методе main выгоды каждое исключение, что thrower броски. Ли вызов thrower завершается обычно или резко, сообщение печатается, описывая, что произошло.

Объявление метода thrower должен иметь a throws пункт, потому что это может бросить экземпляры TestException, который является проверенным классом исключений (§11.2). Ошибка времени компиляции произошла бы если throws пункт был опущен.

Заметьте что finally пункт выполняется на каждом вызове thrower, происходит ли исключение, как показано"[thrower(...) сделанный]" вывод, который происходит для каждого вызова.

11.5 Иерархия Исключения

Возможные исключения в программе организуются в иерархии классов, базировался в классе Throwable (§11.5), прямой подкласс Object. Классы Exception и Error прямые подклассы Throwable. Класс RuntimeException прямой подкласс Exception.

Программы могут использовать существующие ранее классы исключений в throw операторы, или определяют дополнительные классы исключений, как подклассы Throwable или любого из его подклассов, как соответствующий. Чтобы использовать в своих интересах время компиляции платформы Java, проверяя на обработчики исключений, это типично, чтобы определить самые новые классы исключений как проверенные классы исключений, определенно как подклассы Exception это не подклассы RuntimeException.

Класс Exception суперкласс всех исключений, с которых обычные программы могут хотеть восстановиться. Класс RuntimeException подкласс класса Exception. Подклассы RuntimeException классы исключений непроверенные. Подклассы Exception кроме RuntimeException и его подклассы являются всеми проверенными классами исключений.

Класс Error и его подклассы являются исключениями, с которых обычные программы, как обычно ожидают, не восстановятся. См. спецификацию API Java для подробного описания иерархии исключения.

Класс Error отдельный подкласс Throwable, отличный от Exception в иерархии классов, чтобы позволить программам использовать идиому:

} catch (Exception e) {
поймать все исключения, от которых восстановление может быть возможным, не фиксируя ошибки, от которых восстановление обычно не возможно.

11.5.1 Загрузка и Ошибки Редактирования

Виртуальная машина Java бросает объект, который является экземпляром подкласса LinkageError когда загрузка, редактирование, подготовка, проверка или ошибка инициализации происходят:

11.5.2 Ошибки Виртуальной машины

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


Содержание | Предыдущий | Следующий | Индекс Спецификация языка Java
Третий Выпуск

Авторское право © 1996-2005 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления через нашу форму обратной связи

free hit counter