6

我发现 Java 的异常层次结构令人困惑。Throwable分为Errorand ExceptionRuntimeException继承自Exception

  1. Error是未经检查的异常。为什么不Error继承RuntimeException呢?

  2. Exception是一个检查异常。RuntimeException是一个未经检查的异常,但它继承自Exception. 这不违反里氏替换原则吗?

Throwable如果分为Exception(checked) 和RuntimeException(unchecked) 并Error继承自 ,岂不是更有意义RuntimeExeption

4

4 回答 4

3

我发现 Java 的异常层次结构令人困惑。Throwable分为Error和Exception,RuntimeException继承自Exception。

AThrowable是可以用来展开调用堆栈的任何东西。这应该包括一些 VM 级别的错误(由错误标记)和一些特定于应用程序的错误(由异常标记)

Error是未经检查的异常。那么为什么 Error 不从 RuntimeException 继承呢?

仅仅因为错误不是例外。实际上“捕获”错误没有任何意义。例如。抓到后怎么办OutOfMemoryError。错误旨在标记在 VM 级别发生的严重事件,程序员不一定可以处理

异常是一个检查异常。RuntimeException 是未经检查的异常,但它继承自 Exception。这不违反里氏替换原则吗?

并不真地。实现者想说的是必须始终检查异常。如果您的所有方法都声明了它们抛出的应用程序/库异常类型,那么您的代码将会更简洁。只有在更一般/动态的情况下才应该抛出 RuntimeExceptions,例如NullPointerException开发人员可能没有为这种情况编写代码,但这是一个严重的错误,这在应用程序规范中并未完全提及。

于 2011-08-03T09:58:01.853 回答
3

两个最流行的面向对象框架(Java 和 .NET)中的异常处理设计基于这样一个概念,即是否处理特定异常的问题应该主要取决于它的类型,以及人们将要处理的异常类型。想抓都会有等级关系。我认为 Java 和 .NET 那样做是因为 C++ 那样做,而 C++ 那样做是因为希望避免将任何非原始类型硬编码到语言中。catch在没有可以将所有异常转换为的硬编码类型的情况下,语句不可能知道任何关于它没有明确准备的异常类型的任何信息。如果仅捕获可以解码的异常才有意义,那么catch语句将能够明智地作用于那些类型,并且只有那些派生自语句中的类型的类型。

回想起来,最好catch通过类层次结构以外的其他方式来决定应该对哪些异常采取行动和/或通过特定语句解决哪些异常。除此之外,一次尝试调用方法可能会因为多个问题而失败;如果发生这种情况,与这些问题中的任何catch一个相关联的每一个都应该触发,但只有当所有问题都得到解决后,才能恢复正常执行。不幸的是,Java 和 .NET 都没有任何机制来实现这种行为。

关于层次结构的顶层布局,我认为有一个假设,即方法可能抛出的每一种异常要么总是被直接调用代码预期,要么永远不会被任何调用代码预期。后一种类型的例外被归类为ErrorRuntimeException,而前一种类型的例外被放在别处。在实践中,方法调用者是否期望异常的问题应该与它在层次结构中的位置甚至异常类型无关。方法被声明为的事实throws FooException并不意味着调用代码总是期望异常可能发生。代码调用一个声明为抛出异常的方法是很常见的,但认为调用周围的环境使得在实践中特定调用永远不会抛出。如果确实发生异常,它应该表现得像意外异常,即使外部执行上下文期望捕获该类型的异常。不幸的是,异常处理机制就是这样,我不希望有任何大修。

于 2013-08-13T22:49:17.923 回答
2

我认为更好的层次结构是

可抛出异常 CheckedException RuntimeException 错误

这种层次结构将异常和错误分开(正如@Paarth 所说),并且可以仅捕获所有已检查的异常(没有运行时异常)。但似乎詹姆斯·高斯林的想法不同......

于 2011-08-03T09:56:59.540 回答
0
  1. Error 不是 Exception 的子类,因为它并不意味着要捕获(一旦发生错误,通常不再期望程序运行)。所以我相信错误在层次结构中应该有更高的位置。

  2. 它不应该违反 Liskov 替换,因为可以根据需要捕获 RuntimeException,但只是不强制执行。

于 2011-08-03T10:00:12.353 回答