4

Working with objects we use 3 basic steps:

  1. Declaration
  2. Instantiation
  3. Initialization

And my question is about what steps must be done in () part of try-with in order auto close on resource to be made.

Example 1 - will FileReader object be auto closed in this code:

try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
{
//some code;
} 

Example 2 - will the buf2 be auto closed in this code:

private static BufferedReader buf1;

public static void main(String[] args) throws IOException {
    //some code
    try (BufferedReader buf2 = buf1)
    {

    } 
 }

P.S. Someone supposes that this question is duplicate of Try With Resources vs Try-Catch . It is not. That question is about difference between try-catch and try-with-resources. My question is about details of try-with.

Community
  • 1
  • 1
Pavel_K
  • 10,748
  • 13
  • 73
  • 186
  • 3
    Sounds like a homework question, but here's a hint: try-with-resources *requires* that the declared variable implements `AutoCloseable`, and will call `close()` in an implicit finally block. – Andreas Sep 06 '15 at 11:35
  • 1
    Preparing (studying) for a certification *is* homework. Googling OCPJP will even link to an "Oracle University" site. --- Maybe the first paragraph of the Java Tutorial on [The try-with-resources Statement](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) will help you. – Andreas Sep 06 '15 at 11:41
  • 1
    If you're really serious about learning Java, you shouldn't be afraid to experiment. Create an AutoCloseable class. Add a System.out.println statement in the close() method. Use the above code with that class instead of BufferedReader. See if something is printed. Or just add a debugger breakpoint in BufferedReader.close() and see if it's reached. – JB Nizet Sep 06 '15 at 12:28
  • @JB Nizet Thank you for your time. I am not afraid. The matter is that I prefer to understand principles instead of any case. And I wrote here as I hope someone will give the main principle what cases auto close will be made. – Pavel_K Sep 06 '15 at 13:01

2 Answers2

7

Whenever language related details are needed, the most complete reference is the Java Language Specification (just Google it). For the try-with-resources statement, you can read section 14.20.3 which states that the following:

try ({VariableModifier} R Identifier = Expression ...)
    Block

is translated to

{
   final {VariableModifierNoFinal} R Identifier = Expression; 
   Throwable #primaryExc = null;
   try ResourceSpecification_tail
      Block catch (Throwable #t) {
         #primaryExc = #t;
         throw #t;
      } finally {
         if (Identifier != null) {
            if (#primaryExc != null) { 
               try { 
                  Identifier.close(); 
               } catch (Throwable #suppressedExc) { 
                  #primaryExc.addSuppressed(#suppressedExc);
               }
            } else {
               Identifier.close();
            }
         }
     }
}

In your first example, the resource R is BufferedReader, the Identifier is br and the Expression is new BufferedReader(new FileReader(filePath)). It follows that only the BufferedReader is closed in the implicit finally block. The finally block will not call close on the FileReader because it is not part of the resource declaration itself. However, it happens that the implementation of BufferedReader.close() internally calls the close method of the wrapped FileReader. So the answer to the first question is yes simply because the wrapper object closed it (following the common wisdom that a resource should release any wrapped resource when being itself released), not because of the try-with-resources.

In the second example:

private static BufferedReader buf1;

public static void main(String[] args) throws IOException {
    //some code
    try (BufferedReader buf2 = buf1)
    {

    } 
}

the answer depends on the some code. Here buf2 and buf1 both refer to the same object in memory. If this "some code" initializes buf1 to some object, then this object will be closed since buf2 also refers to it. If not and buf1 is null (and therefore buf2 is null), then nothing will be closed because of the null check in the implicit finally shown above.

M A
  • 71,713
  • 13
  • 134
  • 174
1
  1. FileReader will be closed. But that is not because it is in the try statement. It is because when BufferedReader is closed, it calls close() on FileReader as well. For a counter example, I have a class called X that implements AutoCloseable. And that class needs a Foo object in its constructor. So I write:

    try (X x = new X(new Foo())) {
    
    }
    

Will Foo be closed? It doesn't even implement AutoCloseable!

  1. I wrote the following to test this:

    BufferedReader buf1 = null;
    try (BufferedReader buf2 = buf1) {
    
    }
    

And it worked perfectly fine, no exceptions! My guess is that at the end of the try statement, it checks whether the object is null. If it is not, then close it. So in this case, because buf2 is null, it can't be closed.

Sweeper
  • 213,210
  • 22
  • 193
  • 313