78

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 } 
2
  • 12
    This is being addressed in Java 9. See JDK-8068949. Commented Feb 9, 2015 at 16:35
  • 12
    @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.) Commented Mar 24, 2017 at 22:04

6 Answers 6

17

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.

Sign up to request clarification or add additional context in comments.

1 Comment

java9 still does not support OP's case.
11

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; } ); 

8 Comments

+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.
sure it can be done, it's just more work, they didn't think it's worth it.
IMHO, this is an abuse of lambdas. There is 0 benefit, and it makes the code harder to read. Don't do this.
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).
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.
|
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.

5 Comments

I am using resource -- for its side-effects in its <init>() and close()
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 staticing your Lock class.
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.
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.
that was absolutely terrible decision. try with resources could be used to make block closures. Such a shortsightedness
2

With the release of Java 22, which introduced Unnamed Variables and Patterns, you can mark unused variables by replacing their names with an underscore _.

Here is an example of how your code might look:

try (var _ = lock.writeLock()) { // do something } 

Comments

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".

4 Comments

You'ved provided a good reason to allow declaration in the try-with-resources. The OP asks why it's required.
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.
Sorry for confusion; I realize the ResourceSpecification block introduced a local variable, my question is why it has to be named.
Can you please edit your answer? In its current form it does not answer my question
0

Span creation for metrics and monitoring and thread locals are common case of wanting an unnamed resource, where instead the Java compiler could create a name behind the scenes on which it would call the close for the AutoCloseable.

try(createSpan()) { // actions in the monitored span } // span is complete 

The _ usage is a little better, but still unnecessarily verbose.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.