Использование оператора throw
Помимо того, что предопределенная исключительная ситуация может быть возбуждена исполняющей системой Java, программист сам может явно породить ошибку. Делается это с помощью оператора throw.
Например:
... public int calculate(int theValue) {
if( theValue < 0) {
throw new Exception(
"Параметр для вычисления не должен
быть отрицательным");
}
}
...
В данном случае предполагается, что в качестве параметра методу может быть передано только положительное значение; если это условие не выполнено, то с помощью оператора throw порождается исключительная ситуация. (Для успешной компиляции также требуется в заголовке метода указать throws Exception - это выражение рассматривается ниже.)
Метод должен делегировать обработку исключительной ситуации вызвавшему его коду. Для этого в сигнатуре метода применяется ключевое слово throws, после которого должны быть перечислены через запятую все исключительные ситуации, которые может вызывать данный метод. То есть приведенный выше пример должен быть приведен к следующему виду:
...
public int calculate(int theValue)
throws Exception {
if( theValue < 0) {
throw new Exception(
"Some descriptive info");
}
}
...
Таким образом, создание исключительной ситуации в программе выполняется с помощью оператора throw с аргументом, значение которого может быть приведено к типу Throwable.
В некоторых случаях после обработки исключительной ситуации может возникнуть необходимость передать информацию о ней в вызывающий код.
В этом случае ошибка появляется вторично.
Например:
... try {
...
}
catch(IOException ex) {
... // Обработка исключительной ситуации ...
// Повторное возбуждение исключительной
// ситуации throw ex;
}
Рассмотрим еще один случай.
Предположим, что оператор throw применяется внутри конструкции try-catch.
try {
...
throw new IOException();
...
}
catch(Exception e) {
...
}
В этом случае исключение, возбужденное в блоке try, не будет передано для обработки на более высокий уровень иерархии, а обработается в пределах блока try-catch, так как здесь содержится оператор, который может это исключение перехватить. То есть произойдет неявная передача управления на соответствующий блок catch.
Проверяемые и непроверяемые исключения
Все исключительные ситуации можно разделить на две категории: проверяемые (checked) и непроверяемые (unchecked).
Все исключения, порождаемые от Throwable, можно разбить на три группы. Они определяются тремя базовыми типами: наследниками Throwable - классами Error и Exception, а также наследником Exception - RuntimeException.
Ошибки, порожденные от Exception (и не являющиеся наследниками RuntimeException ), являются проверяемыми. Т.е. во время компиляции проверяется, предусмотрена ли обработка возможных исключительных ситуаций. Как правило, это ошибки, связанные с окружением программы (сетевым, файловым вводом-выводом и др.), которые могут возникнуть вне зависимости от того, корректно написан код или нет. Например, открытие сетевого соединения или файла может привести к возникновению ошибки и компилятор требует от программиста предусмотреть некие действия для обработки возможных проблем. Таким образом повышается надежность программы, ее устойчивость при возможных сбоях.
Исключения, порожденные от RuntimeException, являются непроверяемыми и компилятор не требует обязательной их обработки.
Как правило, это ошибки программы, которые при правильном кодировании возникать не должны (например, IndexOutOfBoundsException - выход за границы массива, java.lang.ArithmeticException - деление на ноль). Поэтому, чтобы не загромождать программу, компилятор оставляет на усмотрение программиста обработку таких исключений с помощью блоков try-catch.
Исключения, порожденные от Error, также не являются проверяемыми. Они предназначены для того, чтобы уведомить приложение о возникновении фатальной ситуации, которую программным способом устранить практически невозможно (хотя формально обработчик допускается). Они могут свидетельствовать об ошибках программы, но, как правило, это неустранимые проблемы на уровне JVM. В качестве примера можно привести StackOverflowError (переполнение стека), OutOfMemoryError (нехватка памяти).
Если в конструкции обработки исключений используется несколько операторов catch, классы исключений нужно перечислять в них последовательно, от менее общих к более общим. Рассмотрим два примера:
try {
...
}
catch(Exception e) {
...
}
catch(IOException ioe) {
...
}
catch(UserException ue) {
...
}
Рис. 10.1.Иерархия классов стандартных исключений.
Читать дальше