我突然意识到我从未见过一个异常层次结构,为此创建子类但捕获父类实际上是有用的(当然,除了基本的Exception类,具有)得出)。
异常层次结构是否真的有用,xor是否应该从语言的基本异常类派生所有异常?
答案 0 :(得分:5)
当您需要在不同位置捕获不同的粒度时,异常层次结构对于将相关的异常分组在一起非常有用。
将所有应用程序异常放在一个地方是最常见的用例。这使您可以在任何时候捕获MyAppException
来捕获来自应用程序的所有错误,但在适当时仍会捕获更具体的异常。 (在.NET中,ApplicationException
类是为此而设的,但由于各种原因它已被弃用。)
但您也可以在模块边界或任何其他有意义的方式将异常分组。将FooModuleException
用于来自Foo
模块的异常,但捕获并处理FooModuleMustFrobnicate
特别是Foo
内部的{{1}}。或任何同等情况。
我在不同的时间使用了所有这些模式。
答案 1 :(得分:1)
我从未为整个应用程序创建单个异常层次结构,因为异常通常会带来不同的语义,因此需要以不同的方式处理。
一些例外通知系统故障,另一个例外通知有关错误,另一些例外 - 关于某些异常情况,可以在更高级别上优雅地恢复。
对于这种“业务逻辑”异常,异常层次结构可以帮助您在覆盖后代中的某些方法时不违反开放原则。
请考虑以下示例:
public abstract class Base
{
/// Perform some business-logic operation
/// and throw BaseFooException in certain circumstances
public abstract void Foo();
}
public class Derived1 : Base
{
/// Perform some business-logic operation
/// and throw DerivedFooException in certain circumstances.
/// But caller could catch only BaseFooException
public abstract void Foo() {}
}
class BaseFooException : Exception {}
class DerivedFooException : BaseFooException {}
异常层次结构在自定义框架或特定库中可能会有所帮助,但在一般情况下(在业务应用程序中)我认为创建一个深度和广泛的异常层次结构并不是一个好主意。
答案 2 :(得分:1)
TL; DR
Error
)和&#34;正常&#34;运行时异常。<强烈的>&#34;你需要在不同的地方捕捉不同粒度的概念&#34;是恕我直言的根本缺陷。(除了重申,要区分异常和断言以及其他系统范围内不可恢复的东西。) 我正在慢慢考虑任意类型异常的整个概念,因为我看到它们在C ++,C#和Java中被实现并且应该被用作完全没用< / em>的
问题不在于异常层次结构本身,而是当我编写代码时,异常是例外,我不关心什么类型异常被抛出以捕获它。
在我用C ++,Java和C#编写的所有代码中,我发现 - 用于异常异常,而不是用于控制流 - 不是我要过滤的情况(即抓住或不抓住)他们的&#34;等级&#34;输入即可。 也就是说,在极少数情况下,函数抛出3个不同的异常,我想专门处理其中一个异常,并处理另外两个异常&#34;失败&#34; (如下所述)但我从未在异常层次结构有用的情况下遇到过这种情况,因为我可以通过基类对这两种情况进行有意义的分组。
如果我的程序中的任何操作(我关心的地方)因任何异常而失败,则此操作被视为失败,并且:
我认为Java是三种语言中唯一一种至少具有正确方法的Java,即:
Throwable
未在用户代码中使用Error
你永远不想捕捉的东西 - 只是核心转储Exception
- 对于所有你总是想要捕获的东西(除了界面被拙劣的时候,并且当它真的不应该使用异常时)//
C ++ <stdexcept>
的层次结构有一个正确的基本方法来区分logic_error
- 基本断言 - 和runtime_error
- 意外失败的东西。 (当捕捉时,这些论文的子类基本上无关紧要。)
当然too much内容直接来自std::exception
,因此您无法利用运行时和逻辑错误提供的差异。 (当然,任何代码都可以自由地抛出任何他们想要的东西,所以很可能有一堆逻辑错误派生类真的应该是runtime_errors,反之亦然。
引用另一个答案:
异常层次结构对于分组相关异常非常有用 在一起,当你需要不同的粒度捕捉时 地方。
但根据我的经验,我从不想要&#34;在不同的地方捕捉&#34;,因为它没有意义。
我要么想要捕获,在这种情况下我会捕获所有内容(模块化来自Java的Error
类异常)或者我不想捕获,在这种情况下不需要层次结构,因为没有捕获。
选择opening and reading from a file:
如果有(可能)我特别关心的任何异常类型,因为我可以对它做一些事情(&#34; recover&#34;),那么这根本不应该被报告为异常,因为它是正常的控制流程。 (如果错误是这样的话,我可以在本地做这样的事情。)
如果另一方面,我无法对错误做任何事情,但是将文件操作记录为失败,那么任何捕获粒度都是完全没用的。