Java异常层次结构背后的基本原理

发布于 2024-11-27 19:15:56 字数 583 浏览 1 评论 0原文

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

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

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

如果将 Throwable 分为 Exception (已检查)和 RuntimeException (未检查)和 Error 是否更有意义code> 会继承自 RuntimeException

I find Java's exception hierarchy confusing. Throwable is divided into Error and Exception, and RuntimeException inherits from Exception.

  1. Error is an unchecked exception. Why doesn't Error inherit from RuntimeException then?

  2. Exception is a checked exception. RuntimeException is an unchecked exception, yet it inherits from Exception. Doesn't this violate the Liskov-Substitution-Principle?

Wouldn't it make more sense if Throwable were divided into Exception (checked) and RuntimeException (unchecked), and Error would inherit from RuntimeExeption?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

如日中天 2024-12-04 19:15:56

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

Throwable 是任何可用于展开调用堆栈的东西。这应该包括一些虚拟机级别的故障(由错误标记)和特定于应用程序的某些内容(由异常标记)

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

很简单,因为错误不是异常。实际上“捕获”错误是没有任何意义的。例如。捕获 OutOfMemoryError 后您会做什么。错误旨在标记虚拟机级别发生的严重事件,而程序员不一定可以处理这些事件

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

并不真地。实现者想说的是必须始终检查异常。如果您的所有方法都声明它们抛出哪种类型的应用程序/库异常,您的代码将会更加干净。仅在更一般/动态的情况下才应抛出 RuntimeExceptions,例如 NullPointerException,其中开发人员可能没有针对该情况进行编码,但这是一个严重的错误,这并不完全是应用程序规范中提到的内容。

I find Java's exception hierarchy confusing. Throwable is divided into Error and Exception, and RuntimeException inherits from Exception.

A Throwable is anything that can be used to unwind the call stack. This should include some VM level fault (flagged by an Error) and something application specific (flagged by an Exception)

Error is an unchecked exception. Why doesn't Error inherit from RuntimeException then?

Simply because Errors are not Exceptions. There wouldn't be any point in actually "catching" an Error. For eg. What would you do after catching an OutOfMemoryError. Errors are meant to flag something seriously happened at the VM level which is not necessarily handle-able by the programmer

Exception is a checked exception. RuntimeException is an unchecked exception, yet it inherits from Exception. Doesn't this violate the Liskov-Substitution-Principle?

Not really. What the implementors were trying to say was that Exceptions MUST always be checked. Your code will be cleaner if all your methods declare what sort of application/library Exceptions they throw. RuntimeExceptions should only be thrown in case of more general / dynamic situations such as a NullPointerException where the developer might not have coded for the case but is a serious bug which is not exactly something mentioned in the application spec.

岁吢 2024-12-04 19:15:56

两个最流行的面向对象框架(Java 和 .NET)中异常处理的设计基于以下概念:是否处理特定异常的问题应主要取决于其类型,并且异常的类型将被处理。想要抓住的都会有等级的阶级关系。我认为 Java 和 .NET 这样做是因为 C++ 这样做,而 C++ 这样做是因为希望避免将任何非原始类型硬编码到语言中。如果没有可以将所有异常转换为硬编码类型,则 catch 语句不可能了解任何未明确表示的异常类型的任何信息准备好了。如果仅捕获可解码的异常才有意义,则 catch 语句将能够明智地对这些类型执行操作,并且仅对从该语句中派生的类型执行操作。

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

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

The design of exception handling in the two most popular object-oriented frameworks (Java and .NET) is predicated upon the notion that the question of whether to handle a particular exception should depend primarily upon its type, and that the types of exceptions one will want to catch are going to have a hierarchical class relationship. I think Java and .NET do things that way because C++ did it that way, and C++ did it that way because of a desire to avoid hard-wiring any non-primitive types hard-coded into the language. In the absence of a hard-coded type to which all exceptions may be cast, it's impossible for a catch statement to know anything about any exception type for which it is not explicitly prepared. If it will only make sense to catch exceptions one can decode, a catch statement will be able to sensibly act upon those types, and only those types, which derive from the one in the statement.

In retrospect, it probably would have been better to have the decisions of what exceptions should be acted upon and/or resolved by particular catch statements be determined by some means other than the class hierarchy. Among other things, a single attempt to invoke a method may fail because of multiple problems; if that happens, every catch which is associated with any of those problems should trigger, but only when all of the problems have been resolved should normal execution resume. Unfortunately, neither Java nor .NET has any mechanism to achieve such behavior.

With regard to the top-level layout of the hierarchy, I think there was an assumption that every kind of exception that might be thrown by a method would either always be expected by the immediate calling code or never expected by any calling code. Exceptions of the latter type were classified under Error or RuntimeException, while those of the former type were placed elsewhere. In practice, the question of whether an exception is expected by a method's caller should be independent of its place in the hierarchy or even the exception type. The fact that a method is declared as throws FooException does not mean that calling code is always going to expect that the exception could occur. It's very common for code to call a method which is declared as throwing an exception but believe that the circumstances surrounding the call are such that in practice that the particular call won't ever throw.. If the exception does occur, it should behave like an unexpected exception, even if an outer execution context is expecting to catch an exception of that type. Unfortunately, the exception handling mechanisms are what they are, and I don't expect any major overhaul.

女中豪杰 2024-12-04 19:15:56

我认为更好的层次结构是

Throwable
例外
检查异常
运行时异常
错误

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

I think that even better hierarchy is

Throwable
Exception
CheckedException
RuntimeException
Error

This hierarchy separates Exceptions and Errors (as @Paarth said) and makes it possible to catch all checked exceptions only (without runtime exceptions). But it seems that James Gosling thought different...

街道布景 2024-12-04 19:15:56
  1. Error 不是 Exception 的子类,因为它并不意味着捕获(一旦发生错误,通常程序将不再运行)。因此,正如我所认为的,错误应该在层次结构中占据更高的位置。

  2. 它不应该违反 Liskov 替换,因为如果您愿意,可以捕获 RuntimeException,但只是不强制执行。

  1. Error is not a subclass of Exception because it is not meant to catch (Once an error is occurred usually the program is no longer expected to function). So error should have more higher place in hierarchy as I believe.

  2. It should not violate Liskov substitution because RuntimeException can be catched if you want, but only it's not enforced.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文