Automatic Resource Management, V.2

Joshua Bloch jjb at google.com
Mon Apr 20 08:14:36 PDT 2009


Paul,
Thanks for the feedback.


> > /**
> >  * Returns an array containing all of the exceptions that were
> suppressed,
> >  * typically by the automatic resource management statement, in order to
> >  * deliver this exception.
> >  */
> > public Throwable[] getSuppressedExceptions().
>
> Why not return a List<Throwable> instead of an array (since
> Collections are generally nicer to use)?


I did think about this, but I opted to stick with the pattern in enum types'
values() method.  That decision was made for performance. Arguably the
performance issues are less important here, and the winds of change have
blown further away from arrays since then, so I'm definitely open to
switching this to a List if others think it's the right thing to do.


>  If an array is to be
> returned, is it a copy, or does changing its contents affect the
> Throwable?


A copy.  The spec should have made this explicit, and will do so.


>  Will an empty array or null be returned if there are no
> suppressed exceptions?


It goes without saying (literally) that an empty array will be returned (see
Effective Java Item 43).

>
>
> Would it be useful to distinguish exceptions suppressed by
> AutoCloseable and those suppressed by other mechanisms (e.g. with an
> associated enum or message, or even an EnumMap of <Cause, Exception>)?
>  Why exceptions were suppressed might be useful in future (unless it
> is expected that only AutoCloseable will suppress exceptions, or that
> it is unlikely that there will be multiple suppressors of exceptions).


This feels like overkill to me.

>
>
> > The printStackTrace method should be modified to append the stack traces
> for
> > any suppressed exceptions.
>
> This might be difficult, particularly where there are a number of
> "cause" and "suppressed" exceptions (each of which might have their
> own) - it might be hard to associate each exception with its parent in
> the output (whereas currently "cause" has only one immediate parent
> and so it is easy to follow such a stack trace).


I did think about this, and came to the conclusion that it wasn't so bad.
 The main problem is the "intermingling" of causes and suppressed
exceptions.  I will come up with a format and put an example in the spec.


>  This would also have
> an impact on the TESTING section (where "cause" exceptions should also
> be included).


True!  I'll fix this later today.


>
>
> > *DESIGN FAQ*
>
> It might be nice to answer "Why is the 'try' keyword used instead of
> alternatives such as 'using'?" (though maybe only once the change has
> been released - probably not important at this stage).


Yes.  I'm sure the DESIGN FAQ will grow over time.  As you can see, my
current focus was on code samples for how to achieve specific effects.

>
>
> > *2. Does the construct allow access to resources after an exception is
> > thrown from within the block, but before the resource is closed?*
>
> I didn't really understand why this had to be the case - was it
> because resource variables are final and initialised in order, so if
> one resource fails to initialise it will not be in scope at all, so we
> cannot guarantee that any will be in scope in explicit catch and
> finally clauses?


The only other reasonable rule that I could come up with was that the
finally block was executed before the close, but only if all the resource
declarations complete successfully, and that all resources were in scope,
but these semantics are far less desirable.  Perhaps this rates an FAQ.

 If so, couldn't they just be set to null if they
> were not initialised correctly?


It turns out that this is not an issue, as the catch/finally blocks won't
get executed if any declarations fail.


>  As you say, it is probably not a
> major issue in any case.


Yep.


> > * 3. Does the construct work properly with “decorated” resources?*
> ...
> >     try (FileReader fr = new FileReader(path) {
> >         try (BufferedReader br = new BufferedReader(fr) {
> >             ... // Use buffered reader
> >         }
> >     }
>
> You are missing a closing ) on each of the try lines.


Yep.

>
>
> Could this be rewritten as the following?
>
> try (FileReader fr = new FileReader(path); BufferedReader br = new
> BufferedReader(fr)) {
>           ... // Use buffered reader
> }
>

Yep.  Done.

>
>
> > * 4. Does the construct support resource types whose termination method
> has
> ...
> > with an annotation. But this violates the rule that annotations cannot
> > change the semantics of a program (JLS §9.7). The other is to use an
> actual
>
> I can't see such a rule in the JLS - the closest seems to be "The
> purpose of an annotation is simply to associate information with the
> annotated program element" - is that what is meant?


Yes.  That's how that prose has always been interpreted.

>
>
> > *5. Some failures of the **close** method can be safely ignored (e.g.,
> ...
> > these exceptions are ignored. If you feel you must ignore them, there is
> a
> > workaround, but it isn't pretty:
>
> Could you use a decorator to simplify the code a little, such as:
>
> public class HideAutoCloseableExceptionsAdapter implements AutoCloseable {
>        private final AutoCloseable delegate;
>        public HideAutoCloseableExceptionsAdapter(AutoCloseable delegate) {
>                this.delegate = delegate;
>        }
>        @Override
>        public void close() {
>                try {
>                        delegate.close();
>                } catch (Exception e) {
>                        // Do nothing
>                 }
>        }
> }
>
> static void copy(String src, String dest) throws IOException {
>       InputStream in = new FileInputStream(src);
>        try (new HideAutoCloseableExceptionsAdapter(in)) {
>            try(OutputStream out = new FileOutputStream(dest)) {
>               byte[] buf = new byte[8192];
>               int n;
>               while ((n = in.read(buf)) >= 0)
>                   out.write(buf, 0, n);
>           }
>       }
>   }
> }
>

Yes; you could do that.  Of course you'd have to write a separate decorator
for every such type.  But it's worth mentioning that in the FAQ, and I will
do so.

         Thanks again,

         Josh



More information about the coin-dev mailing list