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

Java 抛出一长串异常vs抛出一个异常vs抛出自定义异常?,java,exception-handling,Java,Exception Handling,我有一个应用程序,它使用两种API方法。这两种方法都会抛出五个以上的异常。所以,如果我只添加一个抛出声明,那么它将变成一个超过10个的列表。(我的方法无法处理十个异常中的任何一个) 我曾读到,抛出一长串异常是一种糟糕的做法。此外,扔(伞)也是一种不好的做法。那么,我该怎么办 添加try-catch块,并在catch块中记录并退出 创建自定义异常类,包装每个异常并抛出自定义异常 是否为所有异常添加抛出声明 抛出异常 添加try-catch块,并在catch块中抛出RuntimeException?

我有一个应用程序,它使用两种API方法。这两种方法都会抛出五个以上的异常。所以,如果我只添加一个抛出声明,那么它将变成一个超过10个的列表。(我的方法无法处理十个异常中的任何一个)

我曾读到,抛出一长串异常是一种糟糕的做法。此外,扔(伞)也是一种不好的做法。那么,我该怎么办

  • 添加try-catch块,并在catch块中记录并退出
  • 创建自定义异常类,包装每个异常并抛出自定义异常
  • 是否为所有异常添加抛出声明
  • 抛出异常
  • 添加try-catch块,并在catch块中抛出RuntimeException?(当前方法)
  • 编辑:添加了选项5

    “2.创建自定义异常类”,但不是针对所有异常类。将异常包装在逻辑组中。例如,您可以有
    XmlWritingException
    paymentgatewayeexception
    DataAccessException
    ,它们根据场景包装不同的异常

    甚至可以(并且更愿意)在不同的包装器中包装相同的异常。例如,如果由于通信问题导致支付失败,则可以在
    PaymentGatewayException
    中包装
    IOException
    ,但如果在使用xml的某些i/o操作期间失败,则可以在
    XmlWritingException
    中包装。所有这些例子都是假设性的,但你明白了

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


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

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

    一如既往,这要视情况而定

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

  • 尽量让你的程序运行的时间尽可能长。这意味着,如果没有配置文件,不要抛出IOException并退出。硬编码一些默认配置。如果没有internet连接,请显示消息,不要退出

  • 有时,可以返回一些特殊的内容(特殊情况模式和空对象模式的变体),而不是抛出异常

  • 考虑在一些特殊情况下实现观察者模式。不要抛出异常,而是通知应该显示消息或执行其他操作的人

  • 不要把它们藏起来。记录所有异常


  • 如果您的API名为Foo,我将创建一个名为FooAPIException的异常。确保将源异常嵌入到FooAPIException中。在记录和显示FooAPIException时,还显示源异常的stacktrace

    例如:

    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);
            }
        }
    }
    

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

    但是,问题是,通过隐藏异常的原因(例如,它是
    IOException
    ),可以隐藏理论上允许更高级别的代码捕获该异常并对其进行处理的信息。在这种情况下,抛出一个
    RuntimeException
    ,并不比这更好,因此您可以用
    RuntimeException
    将它们包装起来


    我仍然会保留那些您可以想象的合理的调用方希望专门捕获并声明它们,或者将它们打包成组。

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

    我通常会尽可能推迟退出政策的决定。退出(如果您是指退出流程)在代码中应该始终是可延迟的,这样您就可以对其进行单元测试

    总的来说,我对例外情况的看法是:

  • 如果错误是一个“业务逻辑问题”,并且调用方可以处理它(通过选择替代逻辑或询问用户要做什么),那么抛出一个自定义检查异常。示例:抛出UserDoesNotExistException以指示数据系统中不存在用户名,并让上一层请求用户创建帐户。在编写时,您可能需要考虑代码的结构是否可以使异常实际上不需要
  • 意外的异常应为运行时(未选中)异常。您希望他们在代码中尽可能地保持不变(线程堆栈很小),并将其作为异常情况处理(通过抛出错误页面、记录错误、向操作员发送警报、反省系统状态并将其包含在错误报告中等)。除非可以添加可用于诊断问题的实际信息,否则不要捕获、包装和重播

  • 如果您没有在该方法中处理异常,那么最好将它们包装到一个或多个自定义异常中并抛出它们,这样您就可以在更高级别上处理它们


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

    抛出的异常是特定系列的成员吗?e、 g.IOException只需存储原始数据,如果有人想要异常,他们可以