The try-with-resources Statement – Exception Handling

7.7 The try-with-resources Statement

Normally, objects in Java are automatically garbage collected at the discretion of the JVM when they are no longer in use. However, resources are objects that need to be explicitly closed when they are no longer needed. Files, streams, and database connections are all examples that fall into this category of objects. Such resources also rely on underlying system resources for their use. By closing such resources, any underlying system resources are also freed, and can therefore be recycled. Resource leakage (i.e., failure to close resources properly) can lead to performance degradation as resources get depleted.

Best practices recommend the following idiom for using a resource:

  • Open the resource—that is, allocate or assign the resource.
  • Use the resource—that is, call the necessary operations on the resource.
  • Close the resource—that is, free the resource.

Typically, all three steps above can throw exceptions, and to ensure that a resource is always closed after use, the recommended practice is to employ a combination of try-catch-finally blocks. The first two steps are usually nested in a try block, with any associated catch clauses, and the third step is executed in a finally clause to ensure that the resource, if it was opened, is always closed regardless of the path of execution through the try-catch blocks.

Example 7.15 shows a naive approach to resource management, that can result in resource leakage. It uses a BufferedReader associated with a FileReader to read a line from a text file (§20.3, p. 1251). The example follows the idiom for resource usage. As we can see, an exception can be thrown from each of the steps. If any of the first two steps throw an exception, the call to the close() method at (4) will never be executed to close the resource and thereby any underlying resources, as execution of the method will be terminated and the exception propagated.

Example 7.15 Naive Resource Management

Click here to view code image

import java.io.EOFException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
public class NaiveResourceUse {
  public static void main(String[] args)
      throws FileNotFoundException, EOFException, IOException {
    // Open the resource:
    var fis = new FileReader(args[0]);             // (1) FileNotFoundException
    var br = new BufferedReader(fis);
    // Use the resource:
    String textLine = br.readLine();               // (2) IOException
if (textLine != null) {
      System.out.println(textLine);
    } else {
      throw new EOFException(“Empty file.”);       // (3) EOFException
    }
    // Close the resource:
    System.out.println(“Closing the resource.”);
    br.close();                                    // (4) IOException
  }
}

Running the program:

Click here to view code image

>
java NaiveResourceUse EmptyFile.txt

Exception in thread “main” java.io.EOFException: Empty file.
      at NaiveResourceUse.main(NaiveResourceUse.java:20)

Running the program:

Click here to view code image

>
java NaiveResourceUse Slogan.txt

Code Compile Compute
Closing the resource.

Example 7.16 improves on Example 7.15 by explicitly using try-catch-finally blocks to manage the resources. No matter how the try-catch blocks execute, the finally block at (4) will always be executed. If the resource was opened, the close() method will be called at (5). The close() method is only called on the BufferedReader object, and not on the FileReader object. The reason is that the close() method of the BufferedReader object implicitly calls the close() method of the FileReader object associated with it. This is typical of how the close() method of such resources works. Also, calling the close() method on a resource that has already been closed normally has no effect; the close() method is said to be idempotent.

Example 7.16 Explicit Resource Management

Click here to view code image

import java.io.EOFException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TryWithoutARM {
  public static void main(String[] args) {
    BufferedReader br = null;
    try {
      // Open the resource:
      var fis = new FileReader(args[0]);             // (1) FileNotFoundException
      br = new BufferedReader(fis);
      // Use the resource:
      String textLine = br.readLine();               // (2) IOException
if (textLine != null) {
        System.out.println(textLine);
      } else {
        throw new EOFException(“Empty file.”);       // (3) EOFException
      }
    } catch (FileNotFoundException | EOFException e) {
      e.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } finally {                                      // (4)
      if (br != null) {
        try {
          System.out.println(“Closing the resource.”);
          br.close();                                // (5) IOException
        } catch(IOException ioe) {
          ioe.printStackTrace();
        }
      }
    }
  }
}

Running the program:

Click here to view code image

>
java TryWithoutARM EmptyFile.txt

java.io.EOFException: Empty file.
      at TryWithoutARM.main(TryWithoutARM.java:20)
Closing the resource.

Running the program:

Click here to view code image

>
java TryWithoutARM Slogan.txt

Code Compile Compute
Closing the resource.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *