Кен Арнольд Джеймс Гослинг
Вид материала | Документы |
Содержание7.4. Операторы try, catch и finally 7.4.1. Условие finally |
- Джеймс трефил, 41001.36kb.
- Джеймс А. Дискретная математика и комбинаторика [Текст] / Джеймс А. Андерсон, 42.79kb.
- Человеческая способность эти ценности производить и использовать; является важнейшей, 110.76kb.
- Джеймс блиш города в полете 1-4 триумф времени вернись домой, землянин жизнь ради звезд, 10495.38kb.
- Джеймс Н. Фрей. Как написать гениальный роман, 2872.12kb.
- Дп «авто интернешнл» Київ, вул. Урицького, 1а Тел. (044) 20-60-333 Факс. (044) 20-60-343, 82.44kb.
- Тема Кол-во страниц, 26.85kb.
- Тема Кол-во страниц, 56.3kb.
- Тема Кол-во страниц, 20.7kb.
- Арнольд И. В. Стилистика современного английского языка, 20.42kb.
7.4. Операторы try, catch и finally
Чтобы перехватить исключение, необходимо поместить фрагмент программы в оператор try. Базовый синтаксис оператора try выглядит следующим образом:
try
блок
catch (тип-исключения идентификатор)
блок
catch (тип-исключения идентификатор)
блок
.....
finally
блок
Тело оператора try выполняется вплоть до возбуждения исключения или до успешного завершения. Если возникает исключение, то по порядку просматриваются все условия catch, пока не будет найдено исключение нужного класса или одного из его суперклассов. Если подходящее условие catch так и не найдено, то исключение выходит из текущего оператора try во внешний, который может обработать его. В операторе try может присутствовать любое количество условий catch, в том числе и ни одного. Если ни одно из условий catch внутри метода не перехватывает исключение, то оно передается в тот фрагмент программы, который вызвал данный метод.
Если в try присутствует условие finally, то составляющие его операторы выполняются после того, как вся обработка внутри try будет завершена. Выполнение finally происходит независимо от того, как завершился оператор — нормально, в результате исключения или при выполнении управляющего оператора типа return или break.
В приводимом ниже примере осуществляется подготовка к обработке одного из исключений, возбуждаемых в replaceValue:
try {
attributedObj.replaceValue("Age", new Integer(8));
} catch (NoSuchAttributeException e) {
// так не должно быть, но если уж случилось - восстановить
Attr attr = new Attr(e.attrName, e.newValue);
attrbuteObj.add(attr);
}
try содержит оператор (представляющий собой блок), который выполняет некоторые действия, в обычных условиях заканчивающиеся успешно. Если все идет нормально, то работа блока на этом завершается. Если же во время выполнения программы в try-блоке возбудилось какое-либо исключение (прямо, посредством throw, либо косвенно, через внутренний вызов метода), то выполнение кода внутри try прекращается, и просматриваются связанные с ним условия catch, чтобы определить, нужно ли перехватывать исключение.
Условие catch чем-то напоминает внедренный метод с одним параметром —типом перехватываемого исключения. Внутри условия catch вы можете пытаться восстановить работу программы после произошедшего исключения или же выполнить некоторые действия и повторно возбудить исключение, чтобы вызывающий фрагмент также имел возможность перехватить его. Кроме того, catch может сделать то, что сочтет нужным, и прекратить свою работу — в этом случае управление передается оператору, следующему за оператором try (после выполнения условия finally, если оно имеется).
Универсальное условие catch (например, перехватывающее исключения типа Exception) обычно говорит о плохо продуманной реализации, поскольку оно будет перехватывать все исключения, а не только то, которое нас интересует. Если воспользоваться подобным условием в своей программе, то в результате при возникновении проблем с атрибутами будет обрабатываться, скажем, исключение ClassCastException.
Условия catch в операторе try просматриваются поочередно, от первого к последнему, чтобы определить, может ли тип объекта-исключения присваиваться типу, объявленному в catch. Когда будет найдено условие catch с подходящим типом, происходит выполнение его блока, причем идентификатору в заголовке catch присваивается ссылка на объект-исключение. Другие условия catch при этом не выполняются. С оператором try может быть связано произвольное число условий catch, если каждое из них перехватывает новый тип исключения.
Поскольку условия catch просматриваются поочередно, перехват исключения некоторого типа перед перехватом исключения расширенного типа является ошибкой. Первое условие всегда будет перехватывать исключение, а второе — никогда. По этой причине размещение условия catch для исключения-суперкласса перед условием для одного из его подклассов вызывает ошибку во время компиляции:
class SuperException extends Exception { }
class SubException extends SuperException { }
class BadCatch {
public void goodTry() {
/* НЕДОПУСТИМЫЙ порядок перехвата исключений */
try {
throw new SubException();
} catch (SuperException superRef) {
// Перехватывает и SuperException, и SubException
} catch (SubException subRef) {
// Никогда не выполняется
}
}
}
В каждом операторе try обрабатывается только один исключительный случай. Если catch или finally возбуждают новое исключение, то условия catch данного try не рассматриваются повторно. Код в условиях catch и finally находится за пределами защиты оператора try. Разумеется, возникающие в них исключения могут быть обработаны любым внешним блоком try, для которого внутренние catch или finally являются вложенными.
7.4.1. Условие finally
Условие finally оператора try позволяет выполнить некоторый фрагмент программы независимо от того, произошло исключение или нет. Обычно работа такого фрагмента сводится к “чистке” внутреннего состояния объекта или освобождению “необъектных” ресурсов (например, открытых файлов), хранящихся в локальных переменных. Приведем пример метода, который закрывает файл после завершения своей работы даже в случае возникновения ошибки:
public boolean searchFor(String file, String word)
throws StreamException
{
Stream input = null;
try {
input = new Stream(file);
while (!input.eof())
if (input.next() == word)
return true;
return false; // поиск завершился неудачно
} finally {
if (input != null)
input.close();
}
}
Если создание объекта оператором new закончится неудачно, то input сохранит свое исходное значение null. Если же выполнение new будет успешным, то input будет содержать ссылку на объект, соответствующий открытому файлу. Во время выполнения условия finally поток input будет закрываться лишь в том случае, если он предварительно был открыт. Независимо от того, возникло ли исключение при работе с потоком или нет, условие finally обеспечивает закрытие файла; благодаря этому экономится такой ограниченный ресурс, как количество одновременно открытых файлов. Метод searchFor объявляет о том, что он возбуждает StreamException, чтобы все порожденные в нем исключения после выполнения завершающих действий передавались в вызывающий фрагмент программы.
Условие finally может также использоваться и для выполнения завершающих действий после операторов break, continue и return — вот почему иногда можно встретить try без соответствующих ему catch. При обработке любого оператора, передающего управление программы в другую точку, выполняются все условия finally. Невозможно покинуть try-блок без выполнения его условия finally.
В приведенном выше примере finally используется и для выполнения завершающих действий в случае нормального возврата по оператору return. Один из самых распространенных случаев использования goto в других языках — необходимость выполнения определенных действий при завершении программного блока, как успешном, так и аварийном. В нашем примере finally обеспечивает закрытие файла и при выполнении оператора return, и при возбуждении исключения.
У условия finally всегда имеется некоторая причина. Она может состоять в нормальном завершении блока try, или в выполнении управляющего оператора наподобие return, или же в возбуждении исключения во фрагменте, заключенном в try-блок. Эта причина запоминается и при выходе из блока finally. Тем не менее, если в блоке finally возникает новая причина выхода (скажем, выполняется управляющий оператор вроде break или return или возбуждается исключение), то она отменяет старую, и о существовании последней забывается. Например, рассмотрим следующий фрагмент:
try {
// ... сделать что-нибудь ...
return 1;
} finally {
return 2;
}
Когда выполняется return внутри блока try, то на входе блока finally код возврата равен 1. Однако внутри самого блока finally возвращается значение 2, так что исходный код возврата забывается. В сущности, если бы в блоке try было возбуждено исключение, то код возврата также был бы равен 2. Если бы блок finally не возвращал никакого значения, а просто завершался нормальным образом, то код возврата был бы равен 1.