UncheckedIOException and suppressed exception
zhong.j.yu at gmail.com
Mon Feb 4 20:17:40 PST 2013
On Mon, Feb 4, 2013 at 9:47 PM, David Holmes <david.holmes at oracle.com> wrote:
> On 5/02/2013 1:39 PM, Zhong Yu wrote:
>> On Mon, Feb 4, 2013 at 7:56 PM, David Holmes<david.holmes at oracle.com>
>>> On 5/02/2013 10:16 AM, Zhong Yu wrote:
>>>> Suppose we have an UncheckedIOException e1, which wraps an IOException
>>>> e2. Then another exception e3 occurs that we want suppress. Should we
>>>> do e1.addSuppressed(e3), or e2.addSuppressed(e3)? That's pretty
>>> I don't see any confusion except for your numbering. You have one
>>> that is inflight, e1, and then e3 occurs. If you want to continue
>>> e1 then e1 is suppressing e3.
>> The catcher of an UncheckedIOException e1 would see it simply as a
>> container, so it'll extract the contained IOException e2, and deal
>> with e2 afterwards, for example, rethrow e2. If e3 was added as e1's
>> suppressed exception, e3 is then lost.
> Then the catch is showing their ignorance of suppressed exceptions. BUt this
> is not specific to this situation. Anytime you catch an exception with a
> cause and a suppression list you have to decide what it is you want to do
> with it.
It is far more likely that UncheckIOException is treated as a shell,
and the shell is discarded (along with information attached to it),
leaving only the contained IOException. That is less likely for
"normal" exceptions that represents errors by themselves.
This is probably going to be a common usage
however it'll lose suppressed exception on e1.
>> This "containing" relation is different from the usual "causal"
>> relation between an exception and its cause. Let's be honest, the only
>> purpose of an UncheckedIOException is to smuggle an IOException as
>> unchecked; UncheckedIOException itself has no "business meaning".
> Again read the Throwable javadoc that Joe pointed out top you. This
> "conversion" situation is one of the primary uses for setting a cause:
I'm certainly aware of this practice, unfortunately it is not a good
practice, since there's no reliable way to uncover the original
> "A second reason that a throwable may have a cause is that the method that
> throws it must conform to a general-purpose interface that does not permit
> the method to throw the cause directly. For example, suppose a persistent
> collection conforms to the Collection interface, and that its persistence is
> implemented atop java.io. Suppose the internals of the add method can throw
> an IOException. The implementation can communicate the details of the
> IOException to its caller while conforming to the Collection interface by
> wrapping the IOException in an appropriate unchecked exception. (The
> specification for the persistent collection should indicate that it is
> capable of throwing such exceptions.) "
>>>> If UncheckedIOException is not a *real* exception, maybe we should
>>>> make it a "control" exception. It should have no stacktrace; it should
>>>> have no cause (the wrapped exception is not a cause); it should not
>>>> contain suppressed exceptions.
>>> Any wrapping exception should have the original exception as its cause.
>>> should this wrapper be any different? Throwable even defines it so:
>>> " Throwing a "wrapped exception" (i.e., an exception containing a cause)
>>> Suppression is about control over which exception is propagating - so
>>> why should this be a special case?
>>>> Maybe it can override addSuppressed() to forward suppressed exceptions
>>>> to the wrapped exception. (Though addSuppressed() is `final`, there's
>>>> no problem to leave a backdoor for another JDK class)
>>> I think your exception processing model is slightly confused here.
>>>> Zhong Yu
More information about the lambda-dev