UncheckedIOException and suppressed exception

Peter Levart peter.levart at gmail.com
Sat Feb 9 07:47:51 PST 2013


On 02/08/2013 03:38 PM, Zhong Yu wrote:
> On Tue, Feb 5, 2013 at 3:47 AM, Peter Levart<peter.levart at gmail.com>  wrote:
>
>>          try (CloseableStream<Path> = ...) {
>>              try {
>>                  ... direct Path operations throwing IOException and/or
>>                  ... Stream<Path> operations throwing UncheckedIOException
>>              }
>>              catch (UncheckedIOException uioe) { throw uioe.getCause(); }
>>          }
>>          catch (EOFException eofe) {
>>              // ...
>>          }
>>          catch (ZipException ze) {
>>              // ...
>>          }
>>          catch (IOException ioe) {
>>              //...
>>          }
> There's a bug - the exception from CloseableStream escapes handling
> and creeps away.
>
> Since closing is hidden in a try-with-resource statement, people often
> forget about it, therefore close() should throw the same type of
> exception as opening. If CloseableStream.close() throws IOException,
> the bug won't exist.

Hi Zhong,

That's true. And that would be dangerous for AutoCloseable resources 
that "buffer" output and "flush" it when closed. But Stream<Path> or any 
potential CloseableStream seems to be an inherently "input" resource. Is 
it really possible that closing an open directory fails on any OS? I 
think that CloseableStream could thrown an IOError in that case, 
indicating that there is really something wrong with the platform logic 
or the state of OS. The linux closedir specifies the following for example:

RETURN VALUE
        The closedir() function returns 0 on success.  On error, -1 is 
returned, and errno is set appropriately.

ERRORS
        EBADF  Invalid directory stream descriptor dirp.

...such error should really not occur...

> I'm still at the position that opening/closing the stream should throw
> UncheckedIOException, so that the entire try-with-resource statement
> throws a consistent exception type.
>
>      try(stream = openStream())
>          using stream
>      catch(UncheckedIOException e)
>          handle e
>
> I'm not convinced that "using stream" could involve IOException; why
> would one call Files.list() to get a Stream<Path>, then turn it into
> Iterator<Path> to operate on files "in the open", why he could simply
> use the good old Files.newDirectoryStream()?

Might be just to filter the files using lambdas? But I agree that most 
of the times the processing of Paths would be done inside the Streams 
API too. I would do it that way...

If all IOExceptions were consistently wrapped with UncheckedIOExceptions 
then when one wanted to deal with several IOException subtypes, (s)he 
would have to do the unwrapping in the handler at the end of 
try-with-resources, like for example the following:

         try (CloseableStream<Path> = ...) {
                 ... Stream<Path> operations throwing UncheckedIOException
         }
         catch (UncheckedIOException uioe) {
             try {
                 throw uioe.getCause();
             }
             catch (EOFException eofe) {
                 // ...
             }
             catch (ZipException ze) {
                 // ...
             }
             catch (IOException ioe) {
                 //...
             }
         }

Not bad but not any better either. Only when it doesn't matter which 
kind of IOException is thrown, the consistent wrapping with 
UncheckedIOException simplifies things. I think it would be necessary to 
try to write some real-world examples, like you proposed, to establish 
the right attitude.

Regards, Peter

> Zhong Yu



More information about the lambda-dev mailing list