26

什么时候你会创建自己的异常类而不是使用 java.lang.Exception?(一直?只有在包外使用?只有在必须包含高级逻辑的情况下?等等......)

4

10 回答 10

25

我认为您需要问自己一个稍微不同的问题“创建新异常给我或使用我的代码的开发人员带来什么好处?” 实际上,它为您或其他人提供的唯一优势是处理异常的能力。这似乎是一个显而易见的答案,但实际上并非如此。您应该只处理可以合理恢复的异常。如果您抛出的异常是一个真正致命的错误,为什么要给开发人员一个错误处理它的机会?

更深入的讨论:自定义例外:您应该何时创建它们?

于 2008-10-26T05:00:26.663 回答
11

原因一:

需要捕捉特定的东西。如果调用代码需要处理特定的异常情况,需要区分自己的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 本身......

于 2008-10-26T11:24:39.523 回答
8

我相信:

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 并不是很麻烦。

于 2008-10-26T12:06:47.550 回答
7

当我想以与其他人不同的方式对待我的异常时。如果我想抓住我的并传播其他人的,或者如果我想抓住别人的并传播我的,或者如果我想抓住两者但以不同的方式对待他们,那么我将为我的异常定义一个单独的类。如果我想对它们一视同仁,要么传播两者,要么捕获两者(并且对捕获的异常做同样的事情),我将使用标准类。

于 2008-10-26T05:01:24.913 回答
6

如果语言运行时或库存在现有异常,请使用它 ELSE 创建您自己的,做好记录,这应该适用于 99% 的情况。

于 2008-10-26T07:36:27.173 回答
4

软件捕捉意义。

几乎没有理由抛出现有异常:JVM 已经为您做到了。您的异常版本并不准确,并且抛出“异常”也没有意义。

DataFormatException由于您编写的解析算法,您可能有一个。然而,这种情况很少见。

当您的程序遇到异常情况时,它几乎总是您的程序独有的。为什么将您的异常情况强制适应现有异常?如果它对您的程序来说是独一无二的,那么......嗯......它是独一无二的。以这种方式命名。

但是,不要为每个唯一消息提供唯一的异常类。一个异常可以有许多变体消息和支持细节。

翻译成 Java 的 Python 经验法则是在包级别定义任何唯一的异常。[在 Python 中,他们建议在“模块”级别出现异常,这并不能准确地转换为 Java。]

于 2008-10-26T17:38:33.387 回答
2

总是从使用常见的异常类开始,然后当需要特别处理它时,改变它。

  1. 第一次创建方法时,让异常通过。

  2. 如果有必须处理的异常,则可以只在 throws 中定义这些异常,或者包装到某个运行时异常或包装自己的 throws 异常。在许多情况下,我更喜欢运行时异常。除非从 API 的角度来看需要,否则应避免定义 throws 定义。

  3. 稍后,当某个调用者似乎需要对异常进行特定处理时,请返回并为其创建新异常。

关键是在知道需要什么之前避免做额外的工作。

于 2008-10-26T06:11:49.403 回答
1

如果某个对象/类/方法有问题,我无法想象专门抛出 java.lang.Exception 。它太通用了——如果你不打算创建自己的异常类,在我看来,API 中至少应该有一个更具体的异常类型。

于 2008-10-26T14:50:18.313 回答
0

当异常与 API 相关时,我会使用 Java API 中的异常。但是,如果出现我自己的 API 独有的异常情况,那么我将为它创建一个异常。例如,如果我有一个 Range 对象,它具有两个属性 min 和 max 以及不变量 min <= max,那么我将创建一个异常 InvalidRangeException。

当我编写代码时,这很有帮助,因为我知道异常是否源于我违反了我自己的条件之一或它来自 Java API 的某些东西。

于 2008-10-26T11:27:39.470 回答
-1

在大多数情况下,创建自己的异常类是没有意义的。

新手程序员倾向于创建自己的异常类,以便他们可以使用更能指示错误类型的名称。因此,您会发现 FTPInitializationException、DAOFactoryException 等类,即使此类异常的处理方式与标准异常的处理方式不同。这显然是一种应该避免的反模式。

于 2008-10-26T05:16:07.987 回答