try-with-resources and null resource (original) (raw)

Tomasz Kowalczewski tomasz.kowalczewski at gmail.com
Tue Jan 25 01:57:06 PST 2011


What if null is an expected (though maybe unwelcome) value and I want to do something with it inside try-with-resources:

ClassLoader classLoader = ...; try(InputStream in = classLoader.getResourceAsStream("foo")) { // may return null

if(in == null) { //let's fallback to some other resource searching scheme. }

}

My understanding is that 'in' is implicitly final and I cannot write any fallback code. When the resource is null I have no way of leaving the t-w-r block without generating exception.

I cannot do:

if(in == null) { in = new FakeInputStreamOrSomething(); }

or:

if(in == null) { in = classLoader.getResourceAsStream("some other resource"); }

Of course I can do a proper null-checking logic before going into t-w-r:

ClassLoader classLoader = ...; InputStream in = classLoader.getResourceAsStream("foo")

if(in == null) { in = // fallback resource loading... }

try(InputStream in2 = in) { }

But that's still ugly.

Thanks for listening, Tomek

On Tue, Jan 25, 2011 at 10:02 AM, Bruce Chapman <brucechapman at paradise.net.nz> wrote:

On 25/01/2011 12:40 p.m., Rémi Forax wrote:

On 01/24/2011 09:00 PM, Joe Darcy wrote:

Rémi Forax wrote:

On 01/24/2011 08:00 PM, Joe Darcy wrote:

On 1/22/2011 5:09 AM, Rémi Forax wrote:

On 01/21/2011 08:38 PM, Joe Darcy wrote:

Rémi Forax wrote:

I think try-with-resources should do a null check before entering in the try block.

4. try(AutoCloseable c = null) { 5.     // nothing 6. } $ java TryWithresourceNPE Exception in thread "main" java.lang.NullPointerException at TryWithresourceNPE.main(TryWithresourceNPE.java:6) I got a NPE from the ends of the try block, I think it will be better to detect the case before entering in the try block like foreach or switch does. And with this code: 5. try(InputStream i = null) { 6.       i.available(); 7. } I got the exception below which is not understandable if you don't know how try-with-resources is translated. $ java TryWithresourceNPE Exception in thread "main" java.lang.NullPointerException at TryWithresourceNPE.main(TryWithresourceNPE.java:6) Suppressed: java.lang.NullPointerException at TryWithresourceNPE.main(TryWithresourceNPE.java:7) I'm not too concerned about that stacktrace since the primary exception points to the right location. But the suppressed exception occurs in a generated code that the user don't write. But that is the whole point of try-with-resources, to allow users to not have to write the messy and error-prone clean-up code. I have no problem if the error come from the close() itself, the stacktrace will be explicit in that case. But here it comes because the spec allows try(...) to be used with null, oh no wait! the generated finally block doesn't allow it. I would assign the responsibility differently: because the programmer uses a null expression to initialize a variable, a NullPointerException is generated when the variable is used.  If the null-initialized variable is used inside the statement, there is an additional suppressed exception because of the guarantee to implicitly call close on the value when the block is exited. The main problem is what if a try-with-resources have a body that don't use the variable. Let suppose I design this interface: interface Transaction extends AutoCloseable { public void close() throw TransactionException; } I want to use it with a try-with-resources to use its marvellous suppressed exceptions management: try(Transaction t = Transactions.getTransaction()) { // I don't use 't' here } here if the transaction is null, it will execute the body and then throws a NPE as a sidekick. I don't think it's the behaviour we want. If you take a look to how try/finally are coded now, you will find a nullcheck before the try or in the finally block. I don't like the idea that a user mistake blow up in a generated code, try-with-resources should protect itself. I think this stack trace can easily be explained to programmers by saying "the suppressed exception comes from the close call you did have to write yourself." You don't have to explain something which is not surprising. New features should be expected to require nonzero explanation simply by virtue of being new. I have no problem to teach why try-with-resources was introduced or when to use it. I just don't want to explain why try-with-resources doesn't behave like all other Java constructs. They all works in a similar way: synchronized(null) { }, for(Object o: null) { }, switch(null) { } why try(Object o = null) {} should have a different semantics ? It depends on your idea of "similar way'. The 'similar way' that correctly describes all these behaviours (including try) is "as soon as (but no sooner than) the value is dereferenced to access a field or call a method" To answer relative to your idea of 'similar way' which focuses on the syntactic parts of the statements, it is because all those examples require the null to be dereferenced prior to executing the block. 'synchronized' because you need to synchronize on an object (not null) before executing the block 'for' because you need to get an Iterator from the Iterable and call next() etc before executing the block 'switch' because you need to evaluate the null to determine which case block to execute (although if the language allowed null as a case then this requirement would disappear) 'try' however does not need to do anything with the null before executing the block. Basically it is just saying remember this till after the block then do something with it (close it). It is the semantics of those statements that requires the NPE for null before the block. Try doesn't have those semantics, switch could be designed either way, but was designed to require it, if it was designed to allow null case for String and enum, then there would be no NPE till maybe in the null case or default case blocks, making it like try. try behaves differently because the other constructs cannot behave like try. Bruce -Joe Rémi

-- Tomasz Kowalczewski



More information about the coin-dev mailing list