18

Java7's try-with-resources is great and all, but I can't wrap my head around why it is required to include the declaration of the resource in the try statement. My gut says the following should be possible:

CloseableResource thing;
try (thing = methodThatCreatesAThingAndDoesSomeSideEffect()) {
    // do some interesting things
}
thing.collectSomeStats();

Alas, this results in a syntax error (cryptically expecting a ;). Moving the type definition/declaration into the try statement works, which of course moves thing into the corresponding scope. I can figure out how to work around this when I want more from my AutoClosable than getting closed, I'm interested in why the compiler requires it like this.

akaIDIOT
  • 9,171
  • 3
  • 27
  • 30

3 Answers3

13

Since Java 9 you can declare and initialize the variable used inside try-with-resources outside the block. The only additional requirement for variable is that it has to be effectively final.
So now it is possible to do:

CloseableResource thing = methodThatCreatesAThingAndDoesSomeSideEffect();
try (thing) {
    // do some interesting things
}
thing.collectSomeStats();

Hope it helps.

Michał Szewczyk
  • 7,540
  • 8
  • 35
  • 47
7

Your version does not clearly define what should be closed, for example

CloseableResource thing;
Parameter a;

try (a = (thing = methodThatCreatesAThingAndDoesSomeSideEffect()).getParameter()) {

also what to do if you write

try (12) {

or something?

ALSO

CloseableResource thing1 = methodThatCreatesAThingAndDoesSomeSideEffect();
CloseableResource thing2 = methodThatCreatesAThingAndDoesSomeSideEffect();

try(thing1) {
}

why only close thing1?

So the current syntax force you to create a variable simultaneosly with opening close block.

ALSO2

CloseableResource thing1 = methodThatCreatesAThingAndDoesSomeSideEffect();

try(thing1) {
}

thing1.doSomethingOnClosedResource();

since thing1 remains.

Dims
  • 47,675
  • 117
  • 331
  • 600
  • 1
    Your first point is a good one; leaving the declaration opens up a world of funky expressions that could indeed create a lot of ambiguity on what to close. The second is simply pebkac, something Java tries to avoid a bit too much imho. But I guess that's just personal preference :) – akaIDIOT Dec 12 '12 at 09:39
  • In the first example, A is not closeable so it isn't really a try-with-resource, the second example, you will only open thing 1 so it will only close thing1, don't see a problem with that – Aviram Segal Dec 12 '12 at 09:57
  • @Aviram, what if `A` is `closeable` too? – Dims Dec 12 '12 at 10:12
  • so you initialized a single resource and binded it to thing and a, closing a will close that resource – Aviram Segal Dec 12 '12 at 10:13
  • @Aviram I binded different resources to `a` and `thing` – Dims Dec 12 '12 at 10:15
  • oh didn't notice the getParameter, in that case thing won't even be opened so no need to close it, only a will open and close – Aviram Segal Dec 12 '12 at 10:20
  • @Aviram, so just any value passed to `try` should be closed at the end, then what to do if it is not `Closeable`? – Dims Dec 12 '12 at 10:34
  • If its not closable it should not compile, same as if you declare non closable resource in the correct syntax – Aviram Segal Dec 12 '12 at 11:17
  • 3
    **#1:** The expression can be evaluated and it must result in some instance of `AutoCloseable`, which will be closed: in your case `a` (and `thing`, which is a reference to the same thing). Think of `if (boolean expression)` which is never unclear, no matter how many booleans you mess with in that expression. **#2:** Syntactically, more than one `AutoCloseable` expressions could be provided with the `;` separator. **#3:** Nobody stops me from doing `try (CloseableResource alias = thing1) { ... }` and then `thing1` will still be in scope after that block, so this defence is useless. – Costi Ciudatu Mar 29 '13 at 21:55
2

Reading the java specification I came to this conclusion (although its not implicitly indicates so):

They make you declare the variable and adds an implicit final to it to make sure you can not rebind the variable to something else.

In that case it will be impossible to close the resource because it is no longer binded to the variable.

For Example:

CloseableResource thing;
try (thing = methodThatCreatesAThingAndDoesSomeSideEffect()) {
    thing = null;
    // thing can't be closed now
}

They could make you use final if its outside I guess but it is kind of ugly.


Workaround: You can use finally if you want access to the declared resource:

try (CloseableResource thing = methodThatCreatesAThingAndDoesSomeSideEffect()) {
    // do some interesting things
} finally {
    thing.collectSomeStats();
}

Keep in mind in finally thing is already closed

Aviram Segal
  • 10,962
  • 3
  • 39
  • 52
  • Not really an answer to the *why*-question, but valid nonetheless. – akaIDIOT Dec 12 '12 at 09:42
  • Yea i noticed that after i submitted the answer and started reading the java lang specifications to see if they explain anything but nothing so far – Aviram Segal Dec 12 '12 at 09:46
  • I was happy to read that I can access the resource in the finally block and tried it. But I get "thing cannot be resolved to a variable". So, this workaround does _not_ work. – Stefan Bormann Jan 17 '17 at 07:41