Facts
- The Java SE API says about the
Error
type that it "indicates serious problems that a reasonable application should not try to catch"; also "errors are abnormal conditions that should never occur". - The JLS 11.1.3 "Asynchronous Exceptions" says about
VirtualMachineError
that it is an "internal error or resource limitation in the Java Virtual Machine that prevents it from implementing the semantics of the Java programming language".
Interpretation
Not only the spec explicitly recommends not to catch Error
s, but also says that if VirtualMachineError
happens, then there are no guarantees that the language semantics stands. It appears that the arguments against the Thread.stop
/ThreadDeath
can also be applied to at the very least any VirtualMachineError
. Due to lazy resolution being allowed, the same is true for LinkageError
: no code expects it or guards against it, so when it happens, it may result in corrupting the state of an object just like ThreadDeath
or VirtualMachineError
.
The above seems (to me) enough to decide that there is no robust way to handle Error
s. The only way out I see is to have a Thread.UncaughtExceptionHandler
that calls System.exit
/Runtime.halt
and maybe tries logging the Error
before terminating the VM (a logging attempt may simply fail with another Error
caused by the original one, which is especially obvious if the original Error
is an OutOfMemoryError
).
Questions
- Given that an
Error
represents an abnormal condition that should never occur and that applications should not try to catch it, what are the good reasons to expose theError
type at all in Java SE API instead of handling errors always by terminating the VM without exposing them to applications? - Why do (almost?) all callback methods in the Java SE API, e.g.,
java.nio.channels.CompletionHandler.failed
,CompletionStage.exceptionally
,Flow.Subscriber.onError
, acceptThrowable
, which includesError
, instead of acceptingException
? Effectively, a callback that acceptsThrowable
is not better than code that catches anError
(and the code that completes such a callback has to catch anError
in order to pass it, thus violating the recommendation from theError
class). Such a callback forces a user to either- Also propagate
Throwable
which simply delays handling anError
to a later time and causes more code to run before it is handled, thus increasing the chances of throwing anotherError
(again, obvious for anOutOfMemoryError
). - Wrap
Error
s inException
s, which is only harmful as it effectively hides the fact that anError
occurred by making it impossible to detect in any straightforward way. - Handle
Error
s, which does not seem to be possible other than by terminating the VM.
- Also propagate