Автоматическое закрытие файлов в Java

Автоматическое закрытие файлов в JavaВо многих Java программ, для закрытия фай­лов, которые больше не нужны, метод close() вызывается явным образом.

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

Однако в версию JDK 7 включено новое средство, предоставляющее другой, более рациональный способ управления ресурсами,в том числе и потоками файлового ввода-вывода, автоматизирующий процесс закрытия файлов.

Этот способ основывается на новой разновидности оператора try, называемой оператором try с ресурсами, а иногда еще — автоматическим управлением ресурсами.

Главное преимущество оператора try с ресурсами заключается в том, что он предот­вращает ситуации, в которых файл (или другой ресурс) непреднамеренно остается не­освобожденным и после того, как необходимость в его использовании отпала.

Внимание! Если не позаботиться о своевременном закрытии файлов, то это может привести к утечке памяти и прочим осложнениям в работе программы.

Так выглядит общая форма оператора try с ресурсами:

Здесь описание_ресурса включает в себя объявление и инициализацию ресур­са, такого как файл. По сути, в это описание входит объявление переменной, которая инициализируется ссылкой на объект управляемого ресурса.

По завершении блока try объявленный ресурс автоматически освобождается. Если этим ресурсом является файл, то он автоматически закрывается, что избавляет от необходимости вызывать метод close() явным образом. Оператор try с ресурсами также может включать блоки catch и finally.

Область применимости таких операторов try ограничена ресурсами, которые реа­лизуют интерфейс AutoCloseable, определенный в пакете java.lang.

В этом интер­фейсе определен метод close(). Интерфейс AutoCloseable наследуется интерфейсом Closeable, определенным в пакете java.io. Оба интерфейса реализуются классами потоков, в том числе FileinputStream и FileOutputStream. Следовательно, оператор try с ресурсами может применяться вместе с потоками, включая потоки файлового вво­да-вывода.

В качестве примера ниже приведена версия программы, в которой оператор try с ресурсами используется для автоматического закрытия файла.

Обратите внимание на то, как открывается файл в операторе try с ресурсами:

Здесь сначала объявляется переменная fin типа FileinputStream, а затем этой пе­ременной присваивается ссылка на файл, который выступает в роли объекта, откры­ваемого с помощью конструктора класса FileinputStream.

Таким образом, в данной версии программы переменная fin является локальной по отношению к блоку try и создается при входе в этот блок. При выходе из блока try файл, связанный с перемен­ной fin, автоматически закрывается с помощью неявно вызываемого метода close().

Это означает, что теперь отсутствует риск того, что вы забудете закрыть файл путем яв­ного вызова метода close() . В этом и состоит главное преимущество автоматического управления ресурсами.

Важно понимать, что ресурс, объявленный в операторе try, неявно принимает мо­дификатор final. Это означает, что после создания ресурсной переменной ее значение не может быть изменено. Кроме того, ее область действия ограничивается блоком опе­ратора try.

С помощью одного подобного оператора try можно управлять несколькими ре­сурсами. Для этого достаточно указать список объявлений ресурсов, разделенных точ­кой с запятой.

В качестве примера ниже приведена версия программы CopyFile. В этой версии оба ресурса, fin и fout, управляются одним оператором try.

Обратите внимание на то, как входной и выходной файлы открываются в операторе:

По завершении этого блока try оба файла, на которые ссылаются переменные fin и fout, будут автоматически закрыты.

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

Стоит упомянуть еще об одной особенности оператора try с ресурсами. Вообще говоря, возникшее при выполнении блока try исключение может породить другое ис­ключение при закрытии ресурса в блоке finally.

В случае «обычного» оператора try первоначальное исключение теряется, будучи прерванным вторым исключением. Но в случае оператора try с ресурсами второе исключение подавляется.

При этом оно не те­ряется, а просто добавляется в список подавленных исключений, связанных с первым исключением. Этот список можно получить, вызвав метод getSuppressed(), определенный в классе Throwable.

Не менее важным остается и умение использовать традиционный способ освобождения ресурсов с помощью явного вызова метода close(). И на то имеется ряд веских причин.

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

Во-вторых, переход к использо­ванию версии JDK 7 может произойти не сразу, а следовательно, вы будете вынуждены работать с предыдущей версией данного комплекта. В этом случае воспользоваться пре­имуществами оператора try с ресурсами не удастся, и придется применять традицион­ный способ управления ресурсами.

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

И все же, если вы работаете с версией JDK 7, JDK 8 или более поздней, вариант автоматического управления ресурсами, как более рациональный и надежный, следует считать предпочтительным.

Советуем следующее видео к просмотру: