A lot of boilerplate code is required in explicit resource management using try-catch-finally blocks, and the code can get tedious and complex, especially if there are several resources that are open and they all need to be closed explicitly. The try-with-resources statement takes the drudgery out of associating try blocks with corresponding finally blocks to ensure proper resource management. Any resource declared in the header of the try-with-resources statement will be automatically closed, regardless of how execution proceeds in the try block. The compiler expands the try-with-resources statement (and any associated catch or finally clauses) into basic try-catch-finally blocks to guarantee this behavior. It implicitly generates a finally block that calls the close() method of each resource declared in the header of the try-with-resources statement. There is no need to call the close() method of the resource, let alone provide any explicit finally clause for this purpose.

The close() method provided by the resources declared in a try-with-resources statement is the implementation of the sole abstract method declared in the java.lang.AutoCloseable interface. In other words, these resources must implement the AutoCloseable interface (p. 412).

The syntax of the try-with-resources statement augments the try statement with a try header that comprises a list of resource declaration statements separated by a semicolon (;).

Click here to view code image

try (
resource_declaration_statement
1
; … ; resource_declaration_statement
m
 ) {
 
statements

} catch (
exception_type
1
 |…|
exception_type
k
 
parameter
1
) { // multi-catch
 
statements

}

  catch (
exception_type
n
 
parameter
n
) {                  // uni-catch
 
statements

} finally {                                       // finally
 
statements

}

The syntax shown above is for the extended try-with-resources statement, which has explicit catch and/or finally clauses associated with it. The basic try-with-resources statement has no explicit catch or finally clauses associated with it.

We will use Example 7.17 to illustrate the salient features of the try-with-resources statement. The extended try-with-resources statement at (1) declares and initializes two resources in its try header:

Click here to view code image

try (var fis = new FileReader(args[0]);       // (1) FileNotFoundException
     var br = new BufferedReader(fis)) {
  // …
}

Note that no calls should be made to the close() method of a resource variable that is declared and initialized in the try header. Any catch clause or finally clauses associated with an extended try-with-resources statement will be executed after all the declared resources have been closed. When running Example 7.17 with an empty file, the EOFException is caught and handled after the two resources denoted by the references br and fis have been closed.

The scope of a resource variable is the try block—that is, it is a local variable in the try block. Local variable type inference with var can be used with advantage in declaring resources in this context (§3.13, p. 142). Also, the resource variables are implicitly final, guaranteeing that they cannot be assigned to in the try block, thus ensuring that the right resources will be closed when the close() method is called after the execution of the try block. The closing order of the resources is the reverse order in which they are declared in the try header—that is, the resource declared first in the try header is closed last after the execution of the try block. In Example 7.17, the close() method is first called on the BufferedReader object denoted by the reference br as it is declared last, followed by a call to the close() method of the FileReader object denoted by the reference fis. Note how the idempotent behavior of the close() method in the FileReader object comes into play: It is first called implicitly by the close() method of the BufferedReader object, and then again by virtue of the resource declaration statement in the try header. The try-with-resources statement at (1) can be easily rewritten to avoid this redundant call, where now only the BufferedReader resource is declared, ensuring that the close() method of the FileReader resource will be called only once when the BufferedReader resource is closed:

Click here to view code image

try (var br = new BufferedReader(new FileReader(args[0]))) {
  // …
}

Example 7.17 Using try with Automatic Resource Management (ARM)

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;
import java.util.stream.Stream;

public class TryWithARM {
  public static void main(String[] args) {
    try (var fis = new FileReader(args[0]);        // (1) FileNotFoundExeception
         var br = new BufferedReader(fis)) {
      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();
    }
  }
}

Running the program:

Click here to view code image

>
java TryWithARM EmptyFile.txt

java.io.EOFException: Empty file.
      at TryWithARM.main(TryWithARM.java:15)

Running the program:

Click here to view code image >
java TryWithARM Slogan.txt
Code Compile Compute


Comments

Leave a Reply

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