9

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

我很想看看人们觉得在哪里放置他们的 try/catch 块很有用,希望可能出现一些通用模式。我将用 C++ 发布我的两个示例答案,但任何语言都可以。

请为每个答案提供一个位置和原因。谢谢。

4

9 回答 9

10

不要抓住任何你没有准备好也没有能力处理的东西。

因此,拥有顶级异常处理,以您喜欢的方式对意外异常进行轰炸,然后只捕获您需要的东西(尽可能接近它可能发生的地方)以获得所需的功能。

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

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

于 2009-01-12T09:27:14.280 回答
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,我只捕获我可以处理的错误。当输入不符合我的期望时,我很乐意抛出未捕获的异常。

这个想法是我不希望记录或记录错误。我想把它修好。

于 2009-01-12T09:04:49.143 回答
3

我总是在 main() 中添加一个捕获作为最后的捕获:

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() );
    }
}
于 2009-01-12T08:54:38.837 回答
2

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

我将始终使用所需范围最大的最贪婪的 catch 块,但始终使用最具体的异常类型。由于在 99.99% 的情况下,catch 块的结果是另一个 throw,因此我尝试将完整方法保留在 try 块中。

于 2009-01-12T08:59:57.813 回答
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
}
于 2009-01-12T09:56:34.640 回答
0

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

  1. 从异常源找到调用链上最接近的点,您可以在其中正确处理异常 - 即采取纠正措施,发出事务/操作失败的信号等。(日志本身不应被视为处理异常)所有方法处理程序和抛出者之间应该忽略异常。更喜欢未检查的异常而不是检查的异常,这样异常甚至不会出现在所有这些中间方法中。
  2. 层边界和 API 应该指定它可以使用检查异常抛出的异常,因为处理这些异常是使用它的客户端层/代码合同的一部分。
  3. 编写一个带有handle(Exception e)方法的异常处理程序类,并最初将其发布给团队,并确保每个人都使用它来处理异常。根据不断变化的异常处理场景,稍后继续添加重载的“处理”方法,以便只修改处理程序。
  4. 在进行 catch-and-throw 时,请始终记住链接异常。这可确保报告异常的全部原因。
  5. 切勿多次记录相同的异常跟踪。这使得使用日志文件进行调试变得非常困难。
  6. 顶级方法应该有一个 catch 子句,它将捕获系统可能抛出的任何异常。如果在生产环境中出现问题,这可以防止我们的内部信息泄露到外部世界。这更多的是安全要求。
于 2011-06-23T19:23:22.260 回答
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() );
    }
}
于 2009-01-12T08:55:26.277 回答
0

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

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

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

  • 我需要进行一些清理(如数据库回滚),在这种情况下,我会在清理完成后重新引发异常。
  • 我有更多信息要添加到异常中。
  • 尽管有例外,我的方法可以成功实现其目的。
于 2009-01-12T10:27:07.310 回答
-1

两个地方:

  • 在所有事件处理程序中
  • catch 可以做一些有用的事情的任何位置,比如用对调试有用的信息来补充异常​​。通常,将使用此信息创建一个新异常并抛出。请注意,此新异常的 InnerException(或非 .NET 等效项)应设置为原始异常的异常,以便保留堆栈跟踪之类的内容。
于 2009-01-12T09:03:14.560 回答