Чтение онлайн

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

try {

// .. делаем что-нибудь полезное } са!сИ(НеЗнаюЧтоДелатьСЭтимКонтролируемымИсключением е) { throw new RuntimeException(e);

}

Решение идеально подходит для тех случаев, когда вы хотите «подавить» контролируемое исключение: вы не «съедаете» его, вам не приходится описывать его в своей спецификации исключений, и благодаря цепочке исключений вы не теряете информацию об исходном исключении.

Описанная методика позволяет игнорировать исключение и пустить его «всплывать» вверх по стеку вызова без необходимости писать блоки try-catch и (или) спецификации исключения. Впрочем, при этом вы все равно можете перехватить и обработать конкретное исключение, используя метод getCause, как показано ниже:

// exceptions/TurnOffChecking.java // "Подавление"

контролируемых исключений, import java io *;

import static net mindview.util.Print.*;

class WrapCheckedException {

void throwRuntimeException(int type) { try {

switch(type) {

case 0: throw new FileNotFoundExceptionO; case 1: throw new IOExceptionO; case 2- throw new RuntimeExceptionCTfle Я?"). default: return;

}

} catch(Exception e) {

// Превращаем в неконтролируемое: throw new RuntimeException(e);

}

}

}

class SomeOtherException extends Exception {}

public class TurnOffChecking {

public static void main(String[] args) {

WrapCheckedException wee = new WrapCheckedExceptionO: // Можно вызвать throwRuntimeExceptionO без блока try, // и позволить исключению RuntimeException покинуть метод-wee. throwRuntimeExceptionO); // Или перехватить исключение: for (int i =0; i <4; i++) try {

if(i < 3)

wee throwRuntimeException(i);

else

throw new SomeOtherExceptionO: } catch(SomeOtherException e) {

print("SomeOtherException. " + e); } catch(RuntimeException re) {

try { продолжение &

throw re.getCauseO, } catch(FileNotFoundException e) {

print("FileNotFoundException. " + e); } catch(IOException e) {

print("IOException- " + e); } catch(Throwable e) {

print("Throwable. " + e);

}

}

}

} /* Output-

Fi1eNotFoundException: java.iо.Fi1eNotFoundException

IOException: java.io.IOException

Throwable: java.lang.RuntimeException. Где Я?

SomeOtherExcepti on: SomeOtherExcepti on

*///:-

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

При взгляде на класс TurnOffChecking нетрудно заметить, что вызвать метод throwRuntimeException можно и без блока try, поскольку он не возбуждает никаких контролируемых исключений. Но когда вы будете готовы перехватить исключение, у вас будет возможность перехватить любое из них — достаточно поместить свой код в блок try. Начинаете вы с перехвата исключений, которые, как вы знаете, могут явно возникнуть в коде блока try, — в нашем случае первым делом перехватывается SomeOtherException. В конце вы перехватываете Runtime-Exception и заново возбуждаете исключение, являющееся его причиной (получая последнее методом getCause, «завернутое» исключение). Так извлекаются изначальные исключения, обрабатываемые в своих предложениях catch.

Методика «заворачивания» управляемых исключений в объекты Runtime-Exception встречается в некоторых примерах книги. Другое возможное решение — создание собственного класса, производного от RuntimeException. Перехватывать такое исключение не обязательно, но, если вы захотите, такая возможность существует.

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

Используйте исключения для того, чтобы:

• обработать ошибку на текущем уровне (избегайте перехватывать исключения, если вы не знаете, как с ними поступить);

• исправить проблему и снова вызвать метод, возбудивший исключение;

• предпринять все необходимые действия и продолжить выполнение без повторного вызова метода;

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

• сделать все возможное в текущем контексте и заново возбудить это же исключение, перенаправив

его на более высокий уровень;

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

• завершить работу программы;

• упростить программу (если используемая вами схема обработки исключений делает все только сложнее, значит, она никуда не годится);

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

Резюме

Исключения являются неотъемлемой частью программирования на Java; существует некий барьер, который невозможно преодолеть без умения работать с ними. По этой причине исключения были представлены именно в этой части книги — многими библиотеками (скажем, библиотекой ввода/вывода) просто невозможно нормально пользоваться без обработки исключений.

Одно из преимуществ обработки исключений состоит в том, что она позволяет сосредоточиться на решаемой проблеме, а затем обработать все ошибки в описанном коде в другом месте. Хотя исключения обычно описываются как средство передачи информации и восстановления после ошибок на стадии выполнения, я сильно сомневаюсь, что «восстановление» часто реализуется на практике. По моей оценке, это происходит не более чем в 10% случаев, и даже тогда в основном сводится к раскрутке стека к заведомо стабильному состоянию вместо реального выполнения действий по восстановлению. На мой взгляд, ценность исключений в основном обусловлена именно передачей информации. Java фактически настаивает, что программа должна сообщать обо всех ошибках в виде исключений, и именно это обстоятельство обеспечивает Java большое преимущество перед языками вроде С++, где программа может сообщать об ошибках разными способами (а то и не сообщать вовсе).

Информация о типах

Механизм RTTI (Runtime Type Information) предназначен для получения и использования информации о типах во время выполнения программы.

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

В этой главе рассматриваются способы получения информации об объектах и классах во время выполнения программы в Java. Существует два механизма получения такой информации: «традиционный» механизм RTTI, подразумевающий, что все типы доступны во время компиляции, а также механизм рефлексии (reflection), применяемый исключительно во время выполнения программы.

Необходимость в динамическом определении типов (RTTI)

Рассмотрим хорошо знакомый пример с геометрическими фигурами, основанный на полиморфизме. Обобщенным базовым классом является фигура Shape, а производными классами — окружность Circle, прямоугольник Square и треугольник Triangle.

С04

г'

сО;

Это обычная диаграмма наследования — базовый класс расположен вверху, производные классы присоединяются к нему снизу. Обычно при разработке объектно-ориентированных программ код по возможности манипулирует ссылками на базовый класс (в нашем случае это фигура — Shape). Если вдруг в программу будет добавлен новый класс (например, производный от фигуры Shape ромб — Rhomboid), то код менять не придется. В нашем случае метод draw класса является динамически связываемым, поэтому программист-клиент может вызывать этот метод, пользуясь ссылкой базового типа Shape. Метод draw переопределяется во всех производных классах, и по природе динамического связывания вызов его по ссылке на базовый класс все равно даст необходимый результат. Это и есть полиморфизм.

Поделиться с друзьями: