您想在哪里捕获异常以及为什么?

时间:2009-01-12 08:54:08

标签: design-patterns exception architecture error-handling error-reporting

你喜欢在哪里捕捉异常以及为什么?

我很有兴趣看到人们发现放置他们的try / catch块有用的地方,希望可能出现一些一般的模式。我将用C ++发布我的两个示例答案,但任何语言都可以。

请回答一个地点和原因。感谢。

9 个答案:

答案 0 :(得分:10)

不要抓住任何你不准备和能够处理的东西。

所以,have top-level exception handling in place以意想不到的异常方式轰炸应用程序然后只捕获你需要的东西(尽可能接近它可能发生的地方)以获得所需的功能。

你应该只做以下两件事之一:实际做一些事情来解决/解决问题,或者重新抛出一个更具描述性的异常,它将被捕获的异常作为innerException

编辑:如果你需要finally块(例如释放你在代码中分配的内容)并且你没有任何有用的任何有用的异常可能会弹出相同的逻辑适用:只需要处理它们。相反,使用catch { throw; }将异常重新抛出到更高级别,同时保持所有异常信息不变。 (或者只是省略catch块,我认为/希望做同样的事情?)

答案 1 :(得分:5)

我试图抓住那些我可以处理的异常。

我讨厌这样的代码:

      String s="12";
      Integer i;
        try {
          i = Integer.parseInt(s);
        } catch(ParseException pe) {
          System.out.println("hihihihihihihi!!!);
        }

我特别讨厌的是,这通常做的是无论如何都要中止线程,因为之后三行会有一个对i的访问,它将假设i!= null。

然后你将阅读你的堆栈跟踪并滚动并滚动并滚动日志,直到你发现第一个重大错误导致其他一切崩溃。

我希望Java不会强迫我抓住我无法处理的例外情况。但我能做的就是:

catch(Exception e) {
  throw new RuntimeException(e);
}

我在函数定义中声明了很多“抛出”。

我仍然在梦想有一天Eclipse将在正确的行中自动打开调试器,因为它将获得未捕获的异常。那天,我的方法将打开正确的行。

在Smalltalk等其他语言中,我只捕捉到我能处理的错误。当输入不符合我的期望时,我很高兴地抛出未被捕获的异常。

我的想法是我不希望记录或记录错误。我希望它得到修复。

答案 2 :(得分:3)

我总是在main()中放一个catch作为最后的手段:

int main( int argc, char** argv ) {
    try {
        Application application( argc, argv );
        return application.result();
    }
    catch ( const std::exception& exception ) {
        fprintf( stderr, "%s.\n", exception.what() );
    }
}

答案 3 :(得分:2)

在C#和Java中,我更喜欢不捕获异常。如果我无法避免,我会立即重新抛出RunTime异常。

我将始终使用具有最大范围所需的最贪婪的catch块,但始终使用最具体的异常类型。由于catch块的结果是99.99%的案例中的另一个抛出,我尝试将整个方法保留在try块中。

答案 4 :(得分:1)

我喜欢尝试将我的异常处理代码与其他代码分开,因此我通常创建一个辅助方法来执行实际逻辑,而外部方法只处理异常处理。我一直认为这样可以使代码看起来整洁,并使其更具可读性。

public void stuff() throws MyException
{
    try
    {
        tryStuff();
    }
    catch (SomeLibraryException e)
    {
        logger.log("Some message happened", e);
        throw new MyException(e);
    }
}

public void tryStuff() throws SomeLibraryException
{
   // Do things in here that could throw exceptions
}

答案 5 :(得分:0)

我喜欢在控制器中捕获处理从视图触发的事件的处理程序。如果异常提供了强有力的安全保证,那么这是一个有用的抓点,因为它的高级别足以报告错误,处理程序通常是原子的,并且与用户刚刚完成的事情有关,所以希望他们能够解决发生了什么事。

void Controller::on_edit_entity( const Entity& entity ) {
    try {
        Command::ptr command = new EditEntityCommand( entity );
        push_command( command );
    }
    catch ( const std::exception& exception ) {
        fprintf( stderr, "%s.\n", exception.what() );
    }
}

答案 6 :(得分:0)

在Delphi Windows应用程序中,应用程序的主消息处理循环(即调用堆栈的底部)通过显示消息框来处理异常。在我看来,这是处理异常的最佳场所。

通过在您自己的方法中捕获异常只是为了向用户显示一个消息框,您拒绝任何调用您的方法的代码知道实际发生异常并且方法实际上失败了。

我只会在以下情况下处理异常:

  • 我需要进行一些清理(比如数据库回滚),在这种情况下,我会在清理完成后重新启动异常。
  • 我还有一些信息要添加到例外中。
  • 我的方法可以成功实现它的目的,尽管例外。

答案 7 :(得分:0)

(在我开始之前:我是一个Java人) 我的建议:

  1. 从异常源中找到最接近调用链的点,您可以正确处理异常 - 即采取纠正措施,发出事务/操作失败信号等。(不应将记录本身视为处理异常)处理程序和thrower之间的所有方法都应该忽略异常。优先选择已检查的异常,以便在所有这些中间方法中都不会出现异常。
  2. 层边界和API应使用已检查的异常指定它可以抛出的异常,因为处理这些异常是使用它的客户层/代码的合同的一部分。
  3. 使用handle(Exception e)方法编写异常处理程序类,并将其最初发布给团队,并确保每个人都使用它来处理异常。基于更改异常处理方案,稍后继续添加重载的“句柄”方法,以便只需要修改处理程序。
  4. 始终记得在进行捕捉和抛出时链接异常。这可确保报告异常的完整原因。
  5. 不要多次记录同一个异常跟踪。这使得使用日志文件进行调试非常困难。
  6. 顶级方法应该有一个catch子句,它将捕获系统可能抛出的任何异常。如果上帝保佑生产环境出现问题,这可以防止我们的内部信息泄露给外界。这更像是一项安全要求。

答案 8 :(得分:-1)

两个地方:

  • 在所有事件处理程序中
  • catch可以执行某些有用操作的任何位置,例如使用对调试有用的信息补充异常。通常会使用此信息创建一个新的异常并抛出。请注意,此新异常的InnerException(或非.NET等效项)应设置为原始异常的异常,以便保留堆栈跟踪等内容。