2

I've read that resources initialized in a try-with-resources block are only in scope for the duration of the block.

If that's the case, then how does this code seem to get around that?

public class Main {
    public static void main(String[] args) throws Exception {
        final Main main = new Main();

        try {
            final char[] buffer = new char[10];
            StringReader stringReader = main.testStream();
            System.out.println(stringReader.read(buffer, 0, 10));
        } catch (IOException e) {
            System.out.println("expected IOException caught here"); 
        }

        try {
            HttpResponse response = main.tryResponse();
            response.getEntity();
            System.out.println("should not reach this line if response is out of scope");
        } catch (Exception e) {
            System.out.println("why no IOException here?");
        }
    }

    StringReader tryStream() throws IOException {
        try (StringReader reader = new StringReader("string")) {
            return reader;
        }
    }

    HttpResponse tryResponse() throws IOException {
        CloseableHttpClient client = HttpClientBuilder.create().build();
        HttpGet request = new HttpGet("http://www.google.com");
        try (CloseableHttpResponse response = client.execute(request)) {
            return response;
        }
    }
}

What are java best practices concerning situations like this?

Community
  • 1
  • 1
jordanpg
  • 6,386
  • 4
  • 46
  • 70
  • 1
    This code should . . . not work. Does it really? http://stackoverflow.com/questions/22947755/try-with-resources-and-return-statements-in-java – CollinD Oct 07 '15 at 18:33
  • Well, you'll get a closed `Closeable` back. Is that different than what you thought will happen? – RealSkeptic Oct 07 '15 at 18:37
  • @RealSkeptic Yes, it was. In the case of an `InputStream`, accessing a closed stream throws an exception. Are there other examples of `Closeable` objects that can be used after they are closed? – jordanpg Oct 07 '15 at 18:43

1 Answers1

2

Scope is a compile time concept that governs where names in source code can be used. From the JLS

The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is visible (§6.4.1).

In other words, it doesn't apply to objects (which is a runtime concept), only to the variables (and other named elements) that refer to them.

For your example (assume without the return), it wouldn't compile if you tried to use the variable response outside the try block:

try (CloseableHttpResponse response = client.execute(request)) {    
} 
System.out.println(response); // nope, compilation error

A return statement evaluates the expression it's given (a variable in this case), resolves a value (a reference to a CloseableHttpResponse object), copies that value, and returns it, popping the current method stack frame from the stack and returning execution to the invoking method.

With your try-with-resources statement, the actual return action is preceded by a finally block which invokes close() on the object referenced by the response variable. Presumably, this puts the object in some unusable state. You will probably get run-time exceptions depending on how you then use it (ie. in the method receiving the return value).

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I see, so the terminology is wrong, but more generally, the answer to the question is: there is no spec concerning the state or behavior of closed objects other than that they be closed according the `Closeable` contract? – jordanpg Oct 07 '15 at 19:14
  • @jordanpg That's right. `Closeable` is just an interface. `try-with-resources` is just a [fancy `try-catch-finally`](http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3) that invokes `close` (which is just a method). There are `Closeable` implementations whose `close` methods are no-ops, `ByteArrayInputStream` for example. – Sotirios Delimanolis Oct 07 '15 at 19:17
  • @jordanpg Basically, you should defer to the javadoc (or the implementation if the rest of the documentation is bad) of the type you're using to know what to expect. – Sotirios Delimanolis Oct 07 '15 at 19:18