Конструктор InputFile получает в качестве аргумента строку (String) с именем открываемого файла. Внутри блока try он создает объект FileReader для этого файла. Класс FileReader не особенно полезен сам по себе, поэтому мы встраиваем его в созданный BufferedReader, с которым и работаем, — одно из преимуществ InputFile состоит в том, что он объединяет эти два действия.
Если при вызове конструктора FileReader произойдет сбой, возбуждается исключение FileNotFoundException. В этом случае закрывать файл не нужно, так как он и не открывался. Все
В этом примере блок finally определенно
Метод getLine() возвращает объект String со следующей строкой из файла. Он вызывает метод readLine(), способный возбуждать исключения, но они перехватываются; *гаким образом, сам getLine() исключений не возбуждает. При проектировании обработки исключений вы выбираете между полной обработкой исключения на определенном уровне, его частичной обработкой и передачей далее того же (или другого) исключения и, наконец, простой передачей далее. Там, где это возможно, передача исключения значительно упрощает программирование. В данной ситуации метод getLine()
Метод dispose() должен вызываться пользователем при завершении работы с объектом InputFile. Он освобождает системные ресурсы (такие, как открытые файлы), закрепленные за объектами BufferedReader и (или) FileReader. Делать это следует только тогда, когда работа с объектом InputFile действительно будет завершена. Казалось бы, подобные действия удобно разместить в методе fina-lize(), но, как упоминалось в главе 5, вызов этого метода не гарантирован (и даже если вы знаете, что он
Самый безопасный способ использования класса, который способен выдать исключение при конструировании и требует завершающих действий, основан на использовании вложенных блоков try:
//: exceptions/Cleanup.java
// Гарантированное освобождение ресурсов.
public class Cleanup {
public static void main(String[] args) { try {
InputFile in = new InputFileC'Cleanup java"); try {
String s; int i = 1;
whileC(s = in getLineO) != null) ; // Построчная обработка .. } catch(Exception e) {
System.out.println("Перехвачено Exception в main"). e.printStackTrace(System.out); } finally {
in.disposeO;
}
} catch(Exception e) {
System out println("Сбой при конструировании InputFile"):
}
}
} /* Output:
disposeO успешен
*///:-
Присмотритесь к логике происходящего: конструирование объекта InputFile фактически заключено в собственный блок try. Если попытка завершается неудачей, мы входим во внешнюю секцию catch и метод dispose() не вызывается. Но, если конструирование прошло успешно, мы хотим обеспечить гарантированное завершение, поэтому сразу же после конструирования создается новый блок try. Блок finally, выполняющий завершение, связывается с
Эта универсальная идиома применяется и в тех ситуациях, когда конструктор не выдает исключений. Основной принцип: сразу же после создания объекта, требующего завершения, начинается конструкция try-finally:
//: exceptions/Cleanupldiom java
// За каждым освобождаемым объектом следует try-finally
class NeedsCleanup { // Конструирование не может завершиться неудачно private static long counter = 1,
private final long id = counter++, Л
pub.lic void disposeO {
System out printin("NeedsCleanup " + id + " завершен");
class ConstructionException extends Exception {}
class NeedsCleanup2 extends NeedsCleanup { // Возможны сбои при конструировании, public NeedsCleanup2() throws ConstructionException {}
public class Cleanupldiom {
public static void main(String[] args) { // Секция 1-
NeedsCleanup ncl = new NeedsCleanupO; try {
// .. } finally {
ncl.disposeO.