try-with-resources and null resource
Reinier Zwitserloot
reinier at zwitserloot.com
Thu Jan 27 23:37:43 PST 2011
Using t-w-r with a null resource would do something other than throw an NPE
in the body if the body contains an if-based null check, for example.
--Reinier Zwitserloot
On Fri, Jan 28, 2011 at 8:18 AM, David Holmes <David.Holmes at oracle.com>wrote:
> Reinier Zwitserloot said the following on 01/28/11 16:54:
>
> I don't understand why one couldn't explain t-w-r by showing "if (resource
>> != null) resource.close();" in the finally block.
>>
>
> One could of course do this. But most usages will involve accessing
> resource within the try block, which would result in NPE anyway.
>
>
> It is then your opinion that this code is abusing the t-w-r construct,
>> because Class.getResourceAsStream can return null?
>>
>> try (InputStream introTextStream =
>> getClass().getResourceAsStream("intro.txt")) {
>> ...
>> }
>>
>
> getResourceAsStream is a problematic example as it should not have been
> defined to return null. But that aside ... yes, that is my opinion. If the
> stream here may not exist I have to deal with that fact in my code. But you
> need to expand your example to show what the try block actually attempts to
> do with the stream that might be null. Your expectations in the null case
> will naturally influence what you expect the construct to do.
>
>
> If so, we've clearly progressed into the "Everyone has their own
>> 'feeling', none of them agree with each other, and making language decisions
>> based on these feelings is a silly thing to do" phase. Let's check how often
>> the above occurs. I'm betting it'll be "loads of times".
>>
>
> The question to answer is: what do those "loads of times" do if they
> encounter a null?
>
>
> Also contrast what you'd have to write if the above is not okay:
>>
>> InputStream introTextStream1 = getClass().getResourceAsStream();
>> if (introTextStream1 != null) {
>> try (InputStream introTextStream2 = introTextStream1) {
>> ...
>> }
>> }
>>
>> I assume I don't have to resort to 'feeling' to claim that the above is
>> just bad.
>>
>
> What's the bad part? Having to declare a secondary variable? Certainly not
> ideal, but hardly fatal - we have to do that to capture locals as finals for
> inner class access. Also the secondary variable is a consequence of a
> different decision to limit the expression to be a local variable
> declaration. I wasn't involved in any discussions of that and I think it
> unfortunate that you can't use:
>
> final InputStream istream = getClass().getResourceAsStream();
> if (istream != null) {
> try (istream) {
> ...
> }
> }
>
> provided istream is a reference to a final, or effectively final, value.
>
> To me a null reference is a bad input for try-with-resources and bad input
> should be rejected.
>
> David Holmes
>
> --Reinier Zwitserloot
>>
>>
>>
>>
>> On Fri, Jan 28, 2011 at 7:38 AM, David Holmes <David.Holmes at oracle.com<mailto:
>> David.Holmes at oracle.com>> wrote:
>>
>> Tim Peierls said the following on 01/28/11 00:47:
>> > I don't know about C#, but I like the formulation that can be
>> sloppily
>> > summarized as "t-w-r calls close on non-null resources".
>>
>> So to summarize there are three potential candidates for:
>>
>> try (Resource r = getResource() {
>> // stuff here
>> }
>>
>> I'm ignoring the suppressed exception aspects for simplicity:
>>
>> a) Simple transformation into try-finally (current implemented
>> semantics)
>>
>> Resource r = getResource();
>> try {
>> // stuff here
>> }
>> finally {
>> r.close();
>> }
>>
>> b) Transformation into try-finally with explicit null-check on entry
>>
>> Resource r = getResource();
>> Objects.requireNonNull(r); // heh heh - couldn't resist!
>> try {
>> // stuff here
>> }
>> finally {
>> r.close();
>> }
>>
>> c) Simple transformation into try-finally but only close a non-null
>> resource
>>
>> Resource r = getResource();
>> try {
>> // stuff here
>> }
>> finally {
>> if (r != null)
>> r.close();
>> }
>>
>>
>> Option (a) is, perhaps, the most consistent with preserving the
>> behaviour of current code that would be modified to use the new
>> construct. This construct will be taught by analogy as it is the only
>> effective way to explain things "try-with-resources behaves as-if you
>> had written ....". That said I think existing code would have an
>> explicit null-check to avoid the try-finally in the null case. And I
>> think it is potentially risky to execute the try block only to have NPE
>> thrown later.
>>
>> Option (c) seems appealing in some sense because there's no NPE's at
>> all
>> if you don't use "r", but I think that appeal is superficial. To me the
>> fundamental question to ask is: what is try-with-resources for? And I
>> believe the answer to that is to initialize, use and then clean-up an
>> AutoCloseable object. So to me using try-with-resource on a resource
>> that might be null is simply a mis-use of try-with-resources: if it can
>> be null you can't autoclose it, so trying to is a programming error and
>> programming errors should be detected and reported as early as
>> possible.
>> So to me option (b) is the preferred semantics for this new construct.
>>
>> David Holmes
>>
>>
>>
More information about the coin-dev
mailing list