72

With reference to my question Any risk in a AutoCloseable wrapper for java.util.concurrent.locks.Lock?, I am wondering why the try-with-resource-statement require a named local variable at all.

My current usage is as follows:

try (AutoCloseableReentrantReadWiteLock.Lock l = _lock.writeLock()) {
    // do something
}        

The variable l is unused inside the try block and only pollutes the namespace. From what I can remember the analogous C# using-statement does not require a local named variable.

Is there any reason the following could not have been supported, with an anonymous local variable that is closed at the end of try block?

try (_lock.writeLock()) {
    // do something
}        
Lii
  • 11,553
  • 8
  • 64
  • 88
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • 12
    This is [being addressed in Java 9](https://blogs.oracle.com/darcy/entry/concise_twr_jdk9). See [JDK-8068949](https://bugs.openjdk.java.net/browse/JDK-8068948). – McDowell Feb 09 '15 at 16:35
  • 11
    @McDowell Java 9 is addressing the current behavior that requires defining a _new_ variable, by allowing use of an _existing_ effectively final variable. It does not appear from your link that Java 9 will support auto-closeable resources _without a visible identifier_. ([Discussed here.](http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-January/030864.html)) – William Price Mar 24 '17 at 22:04

4 Answers4

16

The link in the comment by @McDowell reveals the correct answer in a blog post comment by Joe Darcy who led the Java Technology Specification that introduced the try-with-resources statement:

Back in JDK 7, we started with a try-with-resources construct like that allowed a general expression to be used for the resource, including a method call. However, the expert group found by the early draft review (http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html) that

"A possible future change [to the try-with-resources statemenbt] is dropping support for a resource to be specified as a general Expression. Nontrivial specification and implementation complexities arise from allowing a general Expression to be used as resource. A restricted expression that could be an identifier or a PrimaryNoNewArray may suffice. Even the more severe restriction of just allowing an identifier may provide nearly all the additional utility of allowing a full expression (over forcing the declaration of a new resource variable) at a much lower marginal implementation and specification impact."

By the end of JDK 7, what we wanted was a fresh variable declaration for the resource or an existing final / effectively final variable. We only had time to provide the former in 7; in 9, we are providing the latter too.

Zero3
  • 594
  • 2
  • 11
  • 18
10

Among the use cases that they were considering, most would need to access the resource inside the block, for example, open file - read/write file - close file. They would not have made this design decision if they thought there are a lot of use cases where the local variable is unused.

As to why Lock isn't auto-closeable, I think Doug Lea isn't too concerned with syntax matter, he focuses on solving the hard problem. Others can always add syntax sugar on top of his utilities.

Looking forward, try-with-resource probably will fall out of fashion, replaced by lambda. For example

lock.withLock( ()->{ execute-while-holding-the-lock; } );
ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • 1
    +1 for the lamda usage. The rest of is speculative. Though probably correct I am more interested in if there are reasons it cannot be done. – Miserable Variable May 16 '13 at 15:07
  • sure it can be done, it's just more work, they didn't think it's worth it. – ZhongYu May 16 '13 at 15:50
  • 8
    IMHO, this is an abuse of lambdas. There is 0 benefit, and it makes the code harder to read. Don't do this. – Erich Schubert Nov 07 '14 at 16:18
  • "*They would not have made this design decision...*": Yes, they would. Because of lack of time. See my answer. – Zero3 Jan 13 '16 at 02:31
  • 1
    The idea with lamda expressions is nice, but has several major issues: 1) stepping through the code in the debugger becomes a pain 2) the call hierarchy is cluttered with the lamda calls 3) code completion inside lamdas is currently suboptimal (at least in Eclipse Neon). – Martin Häusler Nov 14 '16 at 09:27
  • It's impossible to generalize checked exception types with SAM compatible interfaces, so this kind of use will never fully supplant try-with-resources, i.e. you can't access a specific type of checked exception returned by the execute body. – Jonathan Schneider Oct 23 '17 at 21:07
  • @jkschneider - I guess, in principle, type inference could yield union of exception types `E1 | E2 ...` for some ``. But anyways, as it stands now, exception-transparency isn't well supported through lambda. – ZhongYu Oct 27 '17 at 11:02
  • @ZhongYu this explains well the pitfalls of trying that: https://dzone.com/articles/draft-a-story-of-checked-exceptions-and-java-8-lam – Jonathan Schneider Oct 27 '17 at 22:04
3

As much as I wish it wasn't, the rationale behind it is that the try-with-resources is intended strictly for operations on the item that must be disposed of. It requires a named variable because it expects that you will do something with that variable while you're inside the block. I guess it's like the compiler saying "If you don't plan on actually using the resource, why are you doing a try-with-resources?"

Now you and I know full well that we don't want to actually use the resource: rather, we just want to make sure it's closed when we're done with it so we don't have devs going around locking up the system. But like so many things, they had to make design decisions and being in the minority, we didn't get the feature.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • 11
    I *am* using resource -- for its side-effects in its `()` and `close()` – Miserable Variable Aug 27 '13 at 17:59
  • But you aren't using it inside the block, which is what the primary use case for try-with-resources is. I find it frustrating too, but that's just how it is. You can save yourself some real estate by `import static`ing your Lock class. – corsiKa Aug 27 '13 at 19:17
  • 2
    There are many reasons not to use the resource explicitly inside the block, for example it might be a lock; or held in a ThreadLocal. – Stefan Reich Dec 02 '17 at 16:27
  • 1
    I fully agree with you, Stefan. As I said, i find it frustrating too. It would seem that init and close are not considered "in the block" to the designers of this feature. – corsiKa Dec 02 '17 at 18:23
  • 1
    that was absolutely terrible decision. try with resources could be used to make block closures. Such a shortsightedness – Enerccio May 13 '21 at 07:52
0

I think that inability to use local variable was the trigger for try-with-resource.

Prior to java 1.7 you had to write something like this:

InputStream in = null;
try {
    in = ....;
} finally {
    if (in != null) {
        in.close();
    }
}

There are 2 disadvantages here:

  1. finally block is annoying and have to be null-safe for each closing resource
  2. We must declare resources outside the block just be able to access them in finally block. Therefore we enlarge the scope where the variables are accessible that is bad practice.

Try-with-resource syntax solves both problems:

  1. finally block is not needed at all.
  2. The resource variable remains accessible into try block only, i.e. where it should be known.

This is why the closable resource must be local. Otherwise one of the main disadvantages of try-with-resource syntax is "disabled".

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • 9
    You'ved provided a good reason to *allow* declaration in the try-with-resources. The OP asks why it's *required*. – Andy Thomas May 16 '13 at 13:42
  • The main motivation is clearly avoiding a lot of boilerplate and providing a programmer with a ready-cooked solution to a quite complex and nuanced problem. I think the scope issue is max. 10% of the whole story. – Marko Topolnik May 16 '13 at 13:42
  • Sorry for confusion; I realize the [ResourceSpecification](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3) block introduced a local variable, my question is why it has to be named. – Miserable Variable May 16 '13 at 14:57
  • 3
    Can you please edit your answer? In its current form it does not answer my question – Miserable Variable Oct 21 '13 at 21:08