Automatically
Closing a File
In the preceding section, the
example programs have made explicit calls to close( ) to close a file once it is no longer needed. As mentioned,
this is the way files were closed when using versions of Java prior to JDK 7.
Although this approach is still valid and useful, JDK 7 added a new feature
that offers another way to manage resources, such as file streams, by
automating the closing process. This feature, sometimes referred to as automatic resource management, or ARM for short, is based on an expanded
version of the try statement. The
principal advantage of automatic
resource management is that it prevents situations in which a file (or other
resource) is inadvertently not released after it is no longer needed. As
explained, forgetting to close a file can result in memory leaks, and could
lead to other problems.
Automatic resource management
is based on an expanded form of the try
statement. Here is its general form:
try (resource-specification) { // use the resource
}
Here, resource-specification is a statement that declares and initializes
a resource, such as a file stream. It consists of a variable declaration in
which the variable is initialized with a reference to the object being managed.
When the try block ends, the
resource is automatically released. In the case of a file, this means that the
file is automatically closed. (Thus, there is no need to call close( ) explicitly.) Of course, this
form of try can also include catch and finally clauses. This new form of try is called the try-with-resources statement.
The try-with-resources statement can be used only with those resources that
implement the AutoCloseable
interface defined by java.lang. This
interface defines the close( )
method. AutoCloseable is inherited
by the Closeable interface in java.io. Both interfaces are
implemented by the stream classes. Thus, try-with-resources
can be used when working with streams, including file streams.
As a first example of
automatically closing a file, here is a reworked version of the ShowFile program that uses it:
/* This version of the ShowFile program uses a
try-with-resources statement to automatically close a file after it is no
longer needed.
Note: This code requires JDK 7 or later.
*/
import java.io.*;
class ShowFile {
public static void main(String args[])
{
int i;
First, confirm that a filename has been
specified.
if(args.length != 1) {
System.out.println("Usage: ShowFile
filename"); return;
}
The following code uses a try-with-resources
statement to open
a file and then automatically close it when the
try block is left.
try(FileInputStream fin = new FileInputStream(args[0]))
{
do {
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
} catch(FileNotFoundException e) {
System.out.println("File Not
Found.");
} catch(IOException e) {
System.out.println("An I/O Error
Occurred");
}
}
}
In the program, pay special
attention to how the file is opened within the try statement:
try(FileInputStream fin = new
FileInputStream(args[0])) {
Notice how the
resource-specification portion of the try
declares a FileInputStream called fin, which is then assigned a reference
to the file opened by its constructor. Thus, in this version of the program, the variable fin is local to the try
block, being created when the try is
entered. When the try is left, the
stream associated with fin is
automatically closed by an implicit call to close( ). You don’t need to call close( ) explicitly, which means that you can’t forget to close the
file. This is a key advantage of using try-with-resources.
It is important to understand
that the resource declared in the try
statement is implicitly final. This
means that you can’t assign to the resource after it has been created. Also,
the scope of the resource is limited
to the try-with-resources statement.
You can manage more than one
resource within a single try
statement. To do so, simply separate each resource specification with a
semicolon. The following program shows an example. It reworks the CopyFile program shown earlier so that
it uses a single try-with-resources
statement to manage both fin and fout.
/* A version of CopyFile that uses
try-with-resources.
It demonstrates two resources (in this case
files) being managed by a single try statement.
*/
import java.io.*;
class CopyFile {
public static void main(String args[]) throws
IOException
{
int i;
First, confirm that both files have been
specified.
if(args.length != 2) {
System.out.println("Usage: CopyFile from
to"); return;
}
//Open and manage two files via the try
statement.
try (FileInputStream fin = new
FileInputStream(args[0]);
FileOutputStream fout = new
FileOutputStream(args[1]))
{
do {
i = fin.read();
if(i != -1) fout.write(i); } while(i != -1);
} catch(IOException e) {
System.out.println("I/O Error: " +
e);
}
}
}
In this program, notice how
the input and output files are opened within the try block:
try (FileInputStream fin = new
FileInputStream(args[0]);
FileOutputStream fout = new
FileOutputStream(args[1]))
{
// ...
After this try block ends, both fin and fout will have been closed. If you compare this version of the
program to the previous version, you will see that it is much shorter. The
ability to streamline source code is a side-benefit of automatic resource
management.
There is one other aspect to try-with-resources that needs to be
mentioned. In general, when a try
block executes, it is possible that an exception inside the try block will lead to another
exception that occurs when the resource is closed in a finally clause. In the case of a “normal” try statement, the original exception is lost, being preempted by
the second exception. However, when using try-with-resources,
the second exception is suppressed.
It is not, however, lost. Instead, it is added to the list of suppressed
exceptions associated with the first exception. The list of suppressed
exceptions can be obtained by using the getSuppressed(
) method defined by Throwable.
Because of the benefits that
the try-with-resources statement
offers, it will be used by many, but not all, of the example programs in this
edition of this book. Some of the examples will still use the traditional
approach to closing a resource. There are several reasons for this. First,
there is legacy code that still relies on the traditional approach. It is
important that all Java programmers be fully versed in, and comfortable with,
the traditional approach when maintaining this older code. Second, because not
all project development will immediately switch to a new version of the JDK, it
is likely that some programmers will continue to work in a pre-JDK 7
environment for a period of time. In such situations, the expanded form of try is not available. Finally, there
may be cases in which explicitly closing a resource is more appropriate than
the automated approach. For these reasons, some of the examples in this book
will continue to use the traditional approach, explicitly calling close( ). In addition to illustrating
the traditional technique, these examples can also be compiled and run by all readers in all environments.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.