什么时候你会创建自己的异常类而不是使用 java.lang.Exception?(一直?只有在包外使用?只有在必须包含高级逻辑的情况下?等等......)
10 回答
我认为您需要问自己一个稍微不同的问题“创建新异常给我或使用我的代码的开发人员带来什么好处?” 实际上,它为您或其他人提供的唯一优势是处理异常的能力。这似乎是一个显而易见的答案,但实际上并非如此。您应该只处理可以合理恢复的异常。如果您抛出的异常是一个真正致命的错误,为什么要给开发人员一个错误处理它的机会?
更深入的讨论:自定义例外:您应该何时创建它们?
原因一:
需要捕捉特定的东西。如果调用代码需要处理特定的异常情况,需要区分自己的Exception,而Java区分不同类型的异常,所以需要自己编写。
基本上,如果有人必须写:
catch(ExistingException e) {
if({condition}) {
{ some stuff here}
}
else {
{ different stuff here}
}
}
你可能想写一个特定的扩展;catch 异常匹配比条件更清楚,恕我直言。
请记住:您的新异常可以是RuntimeException 的子类
原因二:
API 整合。如果您编写一个接口并且您有多个实现,那么它们可能会调用不同的 API 并抛出一大堆不同的非运行时异常:
interface MyInterface {
void methodA();
}
class MyImplA {
void methodA() throws SQLException { ... }
}
class MyImplB {
void methodA() throws IOException { ... }
}
您真的希望 MyInterface.methodA 抛出 SQLException 和 IOException 吗?也许然后将可能的异常包装在自定义异常中是有意义的。这又可能是一个 RuntimeException。甚至 RuntimeException 本身......
我相信:
catch (Exception e) {
...
}
... 是应该避免的反模式。您可能希望在应用程序的某处集中广泛捕获,以记录错误并防止整个应用程序终止 - 但将它们分散在任意位置是不好的。
为什么:
try {
if(myShape.isHidden()) {
throw new Exception();
}
// More logic
} catch (Exception e) {
MyApp.notify("Can't munge a hidden shape");
}
所以你试试这个,由于编码错误,myShape 为空。当运行时尝试取消对 myShape 的引用时,会引发 NullPointerException。此代码报告一个隐藏的形状,它应该报告一个空指针。
要么创建你自己的异常,要么在 API 中找到一个适当的特殊异常。扩展 Exception 或 RuntimeException 并不是很麻烦。
当我想以与其他人不同的方式对待我的异常时。如果我想抓住我的并传播其他人的,或者如果我想抓住别人的并传播我的,或者如果我想抓住两者但以不同的方式对待他们,那么我将为我的异常定义一个单独的类。如果我想对它们一视同仁,要么传播两者,要么捕获两者(并且对捕获的异常做同样的事情),我将使用标准类。
如果语言运行时或库存在现有异常,请使用它 ELSE 创建您自己的,做好记录,这应该适用于 99% 的情况。
软件捕捉意义。
几乎没有理由抛出现有异常:JVM 已经为您做到了。您的异常版本并不准确,并且抛出“异常”也没有意义。
DataFormatException
由于您编写的解析算法,您可能有一个。然而,这种情况很少见。
当您的程序遇到异常情况时,它几乎总是您的程序独有的。为什么将您的异常情况强制适应现有异常?如果它对您的程序来说是独一无二的,那么......嗯......它是独一无二的。以这种方式命名。
但是,不要为每个唯一消息提供唯一的异常类。一个异常类可以有许多变体消息和支持细节。
翻译成 Java 的 Python 经验法则是在包级别定义任何唯一的异常。[在 Python 中,他们建议在“模块”级别出现异常,这并不能准确地转换为 Java。]
总是从使用常见的异常类开始,然后当需要特别处理它时,改变它。
第一次创建方法时,让异常通过。
如果有必须处理的异常,则可以只在 throws 中定义这些异常,或者包装到某个运行时异常或包装自己的 throws 异常。在许多情况下,我更喜欢运行时异常。除非从 API 的角度来看需要,否则应避免定义 throws 定义。
稍后,当某个调用者似乎需要对异常进行特定处理时,请返回并为其创建新异常。
关键是在知道需要什么之前避免做额外的工作。
如果某个对象/类/方法有问题,我无法想象专门抛出 java.lang.Exception 。它太通用了——如果你不打算创建自己的异常类,在我看来,API 中至少应该有一个更具体的异常类型。
当异常与 API 相关时,我会使用 Java API 中的异常。但是,如果出现我自己的 API 独有的异常情况,那么我将为它创建一个异常。例如,如果我有一个 Range 对象,它具有两个属性 min 和 max 以及不变量 min <= max,那么我将创建一个异常 InvalidRangeException。
当我编写代码时,这很有帮助,因为我知道异常是否源于我违反了我自己的条件之一或它来自 Java API 的某些东西。
在大多数情况下,创建自己的异常类是没有意义的。
新手程序员倾向于创建自己的异常类,以便他们可以使用更能指示错误类型的名称。因此,您会发现 FTPInitializationException、DAOFactoryException 等类,即使此类异常的处理方式与标准异常的处理方式不同。这显然是一种应该避免的反模式。