Automatic Resource Management, V.2

Paul Martin paul.martin at gmail.com
Mon Apr 20 05:32:33 PDT 2009


Hi,

I've got a few minor comments/questions:

> To support automatic retention of suppressed exceptions (for high-quality
> diagnostics), we add these methods to java.lang.Throwable:
>
...
> /**
>  * 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)?  If an array is to be
returned, is it a copy, or does changing its contents affect the
Throwable?  Will an empty array or null be returned if there are no
suppressed exceptions?

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

> 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).  This would also have
an impact on the TESTING section (where "cause" exceptions should also
be included).

> *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).

> *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?  If so, couldn't they just be set to null if they
were not initialised correctly?  As you say, it is probably not a
major issue in any case.

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

Could this be rewritten as the following?

try (FileReader fr = new FileReader(path); BufferedReader br = new
BufferedReader(fr)) {
           ... // Use buffered reader
}

> * 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?

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

Otherwise the proposal looks good to me.

Regards,

Paul



More information about the coin-dev mailing list