简体   繁体   中英

How FileInputStream instance is automatically created when Closeable interface is implemented by some custom class when using try-with-resources

I have been working with try-with-resources statement.

try(FileReader rd = new FileReader("Test.txt");){} 
catch (Exception e) {e.printStackTrace();}

The benefit of using try with resources is mainly to do with avoiding to specify the finally block to close out resources.

Thats where my research process kicked in.

After doing some debugging, I found out the FileReader extends InputStreamReader . Inside FileReader class this constructor called

public FileReader(File file) throws FileNotFoundException {
  super(new FileInputStream(file));
}

which creates an object of FileInputStream class. FileInputStream extends InputStream which implements Closeable interface .

Inside FileInputStream class close method is being called as below and doing what it needs to do to close out resources using native method.

public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
           channel.close();
        }

        fd.closeAll(new Closeable() {
            public void close() throws IOException {
               close0();
           }
        });
    }

So I understood this is how the close method is being called.

Now what I fail to understand when I implement the Closeable interface with some custom class directly such as

public class MyClass implements Closeable 
    {
        public void close() 
       {
         System.out.println("connection closed...");
       }
    }

and use it like so

try(MyClass rd = new MyClass();)
{} 
catch (Exception e) 
{e.printStackTrace();}

It is still calling the the close method in custom class MyClass automatically without me calling it explicitly. When I ran through debug it is going into FileInputStream class which extends InputStream class which implements Closeable interface. And then finally this method is being called

public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
           channel.close();
        }

        fd.closeAll(new Closeable() {
            public void close() throws IOException {
               close0();
           }
        });
    }

Can someone please explain to me how FileInputStream instance/object is being created?

Thanks in advance.

Background

Before addressing your actual question it's important to understand how try-with-resources works. For that we can look at §14.20.3 of the Java Language Specification (JLS) . Essentially what that chapter tells you is that if you have the following code:

try (AutoCloseable closeable = ...) {
  // try something
}

Note: The try-with-resources statement works with any java.lang.AutoCloseable implementation. The java.io.Closeable interface extends the java.lang.AutoCloseable interface.

Then that's translated by the compiler as if you wrote something like:

AutoCloseable closeable = ...;
Throwable primary = null;
try {
  // try something
} catch (Throwable t) {
  primary = t;
  throw t;
} finally {
  if (closeable != null) {
    if (primary != null) {
      try {
        closeable.close();
      catch (Throwable suppressed) {
        primary.addSuppressed(suppressed);
      }
    } else {
      closeable.close();
    }
  }
}

The above is the translation for a "basic" try-with-resources , where there's no catch or finally block in the original code. When you do have a catch and/or finally block (ie an "expanded" try-with-resources ) like so:

try (AutoCloseable closeable = ...) {
  // try something
} catch (Exception ex) {
  // handle error
} finally {
  // finally...
}

Then it simply wraps what we had before in another try-catch-finally block:

try {
  // "basic" translation
} catch (Exception ex) {
  // handle error
} finally {
  // finally...
}

As you can see, there's nothing particularly special happening here. Everything is rather straightforward and self-contained.


Your Question

To answer your question: A FileInputStream is not implicitly created as part of the try-with-resources statement. What you claim to see when debugging your code is not possible given your MyClass implementation. You must be either debugging a different piece of code or your source code is out-of-sync with the compiled code. My guess is the former. If you were to debug the following:

import java.io.Closeable;
import java.io.IOException;

public class Main {

  public static void main(String[] args) {
    try (MyClass foo = new MyClass()) {
      // try something...
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }

  public static class MyClass implements Closeable {
    
    @Override
    public void close() throws IOException {
      System.out.println("MyClass#close()");
    }
  }
}

You would not see FileInputStream#close() being invoked—not by that code anyway. To see this we can translate the above code according to §14.20.3 of the JLS, which gives:

import java.io.Closeable;
import java.io.IOException;

public class Main {

  public static void main(String[] args) {
    MyClass foo = new MyClass();
    Throwable primary = null;
    try {
      try {
        // try something...
      } catch (Throwable t) {
        primary = t;
        throw t;
      } finally {
        if (foo != null) {
          if (primary != null) {
            try {
              foo.close();
            } catch (Throwable suppressed) {
              primary.addSuppressed(suppressed);
            }
          } else {
            foo.close();
          }
        }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }

  public static class MyClass implements Closeable {

    @Override
    public void close() throws IOException {
      System.out.println("MyClass#close()");
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM