抛出一长串异常vs抛出异常vs抛出自定义异常?

时间:2010-12-23 15:51:50

标签: java exception-handling

我有一个使用两种API方法的应用程序。这两种方法都抛出超过五个例外。所以,如果我只是添加一个throws声明,那么它将成为一个超过十个的列表。 (我的方法无法处理任何十个例外

我读过,抛出一长串异常是一种不好的做法。抛出(伞)异常是一种不好的做法。所以我该怎么做?

  1. 添加一个try catch块,然后在catch块中记录并退出?
  2. 创建自定义异常类,包装每个异常并抛出自定义异常?
  3. 为所有例外添加投票声明?
  4. 抛出异常?
  5. 添加一个try catch块,并在catch块中抛出RuntimeException? (目前的做法)
  6. 修改:添加了选择5.

7 个答案:

答案 0 :(得分:2)

“2。创建自定义异常类”,但不是全部。在逻辑组中包装异常。例如,您可以XmlWritingExceptionPaymentGatewayExceptionDataAccessException根据方案包装不同的例外。

甚至可以(并且首选)将相同的异常包装在不同的包装器中。例如,如果由于通信问题导致付款失败,您可以在IOException中包裹PaymentGatewayException,但如果在使用xml进行某些i / o操作时失败,则可以在XmlWritingException中。所有这些例子都是假设的,但你明白了。

最重要的是 - 将原始异常设置为新异常的原因,这样它就不会丢失。

更新:实际上,如果您不能指望客户端合理地从异常中恢复,那么选项5就可以了。更好的是 - 您创建的自定义异常可以扩展RuntimeException。这就是spring所做的事情,例如,在DataAccessException中包装所有与数据相关的异常。

答案 1 :(得分:2)

如果你的代码的调用者可以想象处理一些异常,那么我会声明你的方法抛出它们并传递它们。如果没有希望,那么我将创建自己的自定义异常,扩展(取消选中)RuntimeException,并抛出自定义异常,并将实际异常链接到其中。

我一般会推迟决定退出到尽可能高的政策。退出(如果您的意思是退出流程)应始终在代码中推迟,以便您可以对其进行单元测试。

总的来说,我对例外的理念是:

  1. 如果错误是“业务逻辑问题”并且调用者可以处理它(通过选择备用逻辑或询问用户要做什么),则抛出自定义检查的异常。示例:抛出UserDoesNotExistException以指示数据系统中不存在用户名,并让下一层请求用户创建帐户。当你处于它的时候,你可能想要考虑代码是否可以以一种实际上不需要异常的方式构建。
  2. 意外的异常应该是运行时(未经检查)异常。您希望它们在很大程度上保持不变的代码(线程堆栈很小),将它们作为异常条件处理(通过抛出错误页面,记录错误,向操作员发送警报,内省)系统的状态,包括错误报告等)。不要捕获,包装和重新抛出,除非您可以添加可用于诊断问题的实际信息。

答案 2 :(得分:1)

一般来说,如果你的方法无法处理异常,它应该重新抛出它们或将它们添加到throws部分。隐藏catch块中的异常似乎是最糟糕的选择。

答案 3 :(得分:1)

一如既往,这取决于。

  1. 这是你的API吗?如果是,则更改它,让它抛出更少的异常。以某种方式处理它们。

  2. 尽量让您的程序尽可能长时间工作。这意味着,如果没有配置文件,请不要抛出IOException并退出。硬编码一些默认配置。如果没有互联网连接,请显示该消息,不要退出。

  3. 有时候,可以返回一些特殊的东西(特殊情况模式和空对象模式的变体)而不是抛出异常。

  4. 考虑针对某些特殊情况实施Observer模式。不要抛出异常,但要通知应该显示消息或做其他事情的人。

  5. 不要隐藏任何一个。记录所有异常。

答案 4 :(得分:1)

如果您的API名为Foo,我会创建一个名为FooAPIException的异常。确保在FooAPIException中嵌入源异常。记录和显示FooAPIException时,还会显示源异常的堆栈跟踪。

例如:

public class FooAPIException extends Exception {
    private Exception root;

    public FooAPIException (Exception e) {
        super(e.getMessage(),e.getErrorCode());
        root = e;
    }

    public Exception getRoot () {
        return root;
    }

// Exception ================================================================
    public String toString () {
        StringBuffer sb = new StringBuffer();

        sb.append("[");
        sb.append(getErrorCode());
        sb.append("][");
        sb.append(getMessage());
        sb.append("]\n");
        sb.append("ROOT CAUSE:");

        Writer write = new StringWriter();
        PrintWriter pw = new PrintWriter(write);
        e.printStackTrace(pw);
        pw.close();
        try {
            write.close();
        } catch (IOException ioe) {/**/}
        root = write.toString();
        sb.append(write);

        return sb.toString();
    }   
}

然后包装API:

public class FooAPI {
    public static method (String params) throws FooAPIException {
        try {
            RealFooAPI.method(params)
        } catch (Exception e) {
            throw new FooAPIException(e);
        }
    }
}

答案 5 :(得分:0)

您可以使用一些自定义异常包装异常。

然而,问题在于,通过隐藏原因异常(例如,它是IOException),您隐藏了理论上允许更高级别的代码捕获该异常的信息具体而言,处理它。在这种情况下,你最好不要抛出RuntimeException,所以你也可以用RuntimeException包裹它们。

我仍然会留下那些你可以想象的合理的来电者,他们希望专门捕捉并专门宣布,或将它们分组。

答案 6 :(得分:0)

如果您没有处理该方法中的异常,最好将它们包装到一个或多个自定义异常中并抛出它们,以便您可以在较高级别处理它们。

您还可以创建自定义未经检查(扩展的RuntimeException)异常,并将抛出的异常包装到自定义运行时异常中。