Justification for the Java Exception Hierarchy

I find the Java exception hierarchy confusing. Throwable is divided into Error and Exception , and RuntimeException inherited from Exception .

  • Error is an unchecked exception. Why RuntimeException Error inherit from RuntimeException , then?

  • Exception is a checked exception. RuntimeException is an unchecked exception, but it inherits from Exception . Does this not violate the Liskov-Substitution principle?

It makes no sense if Throwable were split into Exception (checked) and RuntimeException (unchecked), and Error would inherit from RuntimeExeption ?

+6
source share
4 answers

I find the Java exception hierarchy confusing. Throwable is split into Error and Exception, and RuntimeException is inherited from Exception.

A Throwable is all you can use to unwind a call stack. This should include some VM-level error (marked with an error) and something specific application (marked with an exception)

Error is an uncontrolled exception. Why does Error not inherit from RuntimeException, then?

Just because errors are no exception. In fact, it would not make sense to actually "catch" a mistake. E.g. What would you do after catching OutOfMemoryError . Errors mean that something has happened seriously at the VM level, which is not necessarily handled by the programmer.

Exception - A checked exception. RuntimeException is an unchecked exception, but it inherits from Exception. Does this not violate the principle of the Liskov Deputy?

Not really. What the developers were trying to say was that Exceptions should always be checked. Your code will be cleaner if all of your methods declare what types of applications / libraries they throw. RuntimeExceptions should only be created in case of more general / dynamic situations, such as NullPointerException , where the developer may not have been coded for this case, but is a serious error that is not exactly mentioned in the application specification.

+3
source

The design of exception handling in the two most popular object-oriented environments (Java and .NET) is based on the idea that the question of whether to handle a specific exception should depend primarily on its type and what types of exceptions you want to catch will have a hierarchical relationship of classes. I think Java and .NET do this because C ++ did just that, and C ++ did just that because of the desire to avoid the hard wiring of any non-primitive types that are hard-coded in the language. In the absence of hard code to which all exceptions can be applied, it is impossible for the catch statement to know anything about the type of exception for which it is not explicitly prepared. If it is reasonable to catch exceptions that can be decoded, the catch statement can intelligently act on these types and only those types that follow from what is specified in the instruction.

In retrospect, it would probably be better to have decisions about which exceptions should be taken and / or allowed by specific catch statements, defined in some ways different from the class hierarchy. Among other things, one attempt to invoke a method may fail due to many problems; if this happens, every catch that is associated with any of these problems should be triggered, but only when all problems have been resolved if normal execution resumes. Unfortunately, neither Java nor .NET has any mechanism to achieve this behavior.

Regarding the top-level layout of the hierarchy, I think there was an assumption that any exception that could be thrown by a method would always be expected with an immediate call code or never be expected with any call code. Exceptions of the latter type were classified under Error or RuntimeException , and those that were in the former were placed in another place. In practice, the question of whether an exception will be the expected calling method does not depend on its place in the hierarchy or even the type of exception. The fact that the method is declared as throws FooException does not mean that the calling code always expects this to happen. Very often, a method is called for the code, which is declared as an exception, but believes that the circumstances associated with the call are such that in practice this or that call will never be thrown. If this is an exception, it should behave like an unexpected exception, even if the external execution context expects to receive an exception of this type. Unfortunately, exception handling mechanisms are what they are, and I do not expect major overhauls.

+2
source

I think the hierarchy is even better

Throwable exception CheckedException RuntimeException Error

This hierarchy separates Exceptions and Errors (as @Paarth said) and allows you to catch only checked exceptions (no exceptions at runtime). But it seems that James Gosling thought differently ...

+1
source
  • The error is not a subclass of Exception because it is not intended to catch (as soon as the error occurs, usually the program will no longer function). Thus, the error should have a higher place in the hierarchy, I suppose.

  • It should not violate the Liskov substitution, because a RuntimeException can be caught if you want, but only it does not apply.

0
source

Source: https://habr.com/ru/post/894178/


All Articles