При завершении работы с потоком его надо закрыть с помощью метода close(), который определен в интерфейсе Closeable. Метод close имеет следующее определение:
void close() throws IOException
Этот интерфейс уже реализуется в классах InputStream и OutputStream, а через них и во всех классах потоков.
При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может происходить утечка памяти.
Есть два способа закрытия файла. Первый традиционный заключается в использовании блока try..catch..finally. Например, считаем данные из файла:
import java.io.*;
public class Program {
public static void main(String[] args) {
FileInputStream fin=null;
try
{
fin = new FileInputStream("notes.txt");
int i=-1;
while((i=fin.read())!=-1){
System.out.print((char)i);
}
}
catch(IOException ex){
System.out.println(ex.getMessage());
}
finally{
try{
if(fin!=null)
fin.close();
}
catch(IOException ex){
System.out.println(ex.getMessage());
}
}
}
}
Поскольку при открытии или считывании файла может произойти ошибка ввода-вывода, то код считывания помещается в блок try. И чтобы быть уверенным, что
поток в любом случае закроется, даже если при работе с ним возникнет ошибка, вызов метода close() помещается в блок finally.
И, так как метод close() также в случае ошибки может генерировать исключение IOException, то его вызов также помещается во вложенный блок
try..catch
Но язык Java позволяет использовать более удобную конструкцию, котораяя автоматически вызывает метод close() - конструкция
try-with-resources (try-с-ресурсами). Данная конструкция работает с объектами, которые реализуют интерфейс AutoCloseable.
Так как все классы потоков реализуют интерфейс Closeable, который в свою очередь наследуется от AutoCloseable, то их также можно использовать в данной
конструкции
Синтаксис конструкции следующий:
try(Resource res = ...){
// действия с ресурсом res
}
Данная конструкция также не исключает использования блоков catch, которые также могут размещаться после блока try:
try(Resource res = ...){
// действия с ресурсом res
}
catch(исключение){
// обработка исключения
}
Итак, перепишем предыдущий пример с использованием конструкции try-with-resources:
import java.io.*;
public class Program {
public static void main(String[] args) {
try(FileInputStream fin = new FileInputStream("notes.txt"))
{
int i=-1;
while((i = fin.read()) != -1){
System.out.print((char)i);
}
}
catch(IOException ex){
System.out.println(ex.getMessage());
}
}
}
После окончания работы в блоке try у ресурса (в данном случае у объекта FileInputStream) автоматически вызывается метод close().
Если нам надо использовать несколько потоков, которые после выполнения надо закрыть, то мы можем указать объекты потоков через точку с запятой:
try(FileInputStream fin = new FileInputStream("hello.txt");
FileOutputStream fos = new FileOutputStream("hello2.txt"))
{
//..................
}
Также обратите внимание, что в данном случае ресурс определяется непосредственно в заголовке конструкции try:
try(FileInputStream fin = new FileInputStream("notes.txt"))
Однако ресурс может быть создан и вне этой конструкции, но при передаче в заголовок конструкции try после ее завершения этот ресурс все равно будет закрыт:
import java.io.*;
public class Program {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fin = new FileInputStream("notes.txt");
try(fin)
{
int i=-1;
while((i = fin.read()) != -1){
System.out.print((char)i);
}
} // здесь вызывается fin.close()
}
}