从不在程序中重新抛出异常是不好的做法吗?

时间:2014-08-24 10:14:11

标签: php exception conceptual

我刚刚阅读了一些关于异常的文章,大多数示例都是这样做的:

try{
    conn.close();
} catch(SQLException ex){
    logger.error("Cannot close connection");
    throw new RuntimeException(ex);
}

虽然我曾经这样做过:

    try
    {
        $this->pdo = new PDO($dbInfo[0], $dbInfo[1], $dbInfo[2]);
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    catch(PDOException $e)
    {
        $this->exceptionHandler->displayException($e);
    }

正如您所看到的,我使用一个类来处理异常而不是重新抛出异常。

例如,如果A类使用的实例B使用可以抛出异常的实例C,我将直接在B类中处理它,而不是将其重新抛出到A类。

然而,根据第一个例子,似乎这个人只是将所有子类异常重新抛出到主类(比如使用我的例子)。

我的方法不好吗?

3 个答案:

答案 0 :(得分:1)

在您的displayException()示例中,除了显示异常之外,您没有做任何其他操作(假设该方法执行了名称所暗示的操作)。如果您没有运行依赖于DB活动的任何其他代码,这可能会很好 - 这可能是简单的PHP应用程序/脚本的情况,但Java应用程序几乎不是这种情况。在更复杂的应用程序中,您通常希望中止任何进一步逻辑的执行并在更高级别处理异常,因此您需要重新抛出异常(在Java中,通常作为未经检查的异常而不是选中一项 - PHP只有未经检查的那些。)

关于Java中将已检查的异常转换为未经检查的异常的选择,我强烈推荐文章Effective Java Exceptions。它深入解释了Java异常模型以及何时应该做什么。我想这是一个观点问题,但我认为那里提出的论点是坚实的。

在您给出的特定情况SQLException中,在java社区中有一些共识,它a)不应该是一个检查的异常开始,而b)太笼统,不能传达任何有关实际错误的意义。这就是你经常

的原因
  • 抓住它,将任何相关详细信息添加到例外或日志中,然后将其作为未经检查的例外重新投放或
  • 使用自动执行此操作的异常翻译器like the one in Spring,或者在finally块中例外的情况下使用
  • 使用一种安静地关闭它的辅助方法,例如closeQuietly

答案 1 :(得分:1)

首先澄清:子系统是一个自包含的函数/对象/方法,它有特殊的责任。例如,PDO实例的职责是管理数据库连接并允许您与数据库进行交互。

现在,一旦子系统遇到无法继续当前操作的异常环境,它就会抛出异常。例如,与数据库的连接可能会突然中断,这是一个阻止PDO执行它应该执行的操作的事件。由于子系统无法继续执行它应该做的事情,它放弃发布并拒绝执行其任何更多的代码,因为它没有意义。它通过抛出异常来向上级/来电者发出这种期望失败的信号。

此调用者现在需要处理这种情况。假设调用者也依赖于子系统来完成其任务,那么直接捕获异常可能毫无意义。假设PDO子系统的调用者是数据对象映射器。由于数据库连接失败,数据对象映射器应该做什么?它也无法继续工作。所以它应该重新抛出异常,或者不首先捕获异常。

如果你有一个实际的计划如何处理异常情况,如果你准备好子系统失败并制定应急计划,那么你唯一想要捕获异常的时间就是。比如说,一个外部HTTP请求失败,您有另一个URL可以查询为回退。但除非你有这样的后备计划,否则停止异常毫无意义。让它尽可能地冒泡到可以以有用的方式包含它的点。某些例外可能根本无法包含;在这种情况下,让他们一起冒泡以使用错误页面停止程序。

答案 2 :(得分:0)

只有在计划对异常执行某些操作时才应捕获异常,例如在第一个示例中记录异常。如果您打算根据异常采取纠正措施,则不应重新抛出异常。