您喜欢在哪里捕获异常,为什么?

发布于 2024-07-12 07:35:20 字数 140 浏览 10 评论 0原文

您喜欢在哪里捕获异常,为什么?

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

请为每个答案提供一个地点和原因。 谢谢。

Where do you like to catch exceptions and why?

I'm interested in seeing where people find it useful to put their try/catch blocks in the hope that some general patterns might emerge. I'll post my two example answers in C++ but any language is fine.

One location and reason per answer please. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

眼前雾蒙蒙 2024-07-19 07:35:21

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

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

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

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

In a Delphi Windows Application, the main message handling loop for your application (i.e. at the bottom of the call stack) handles your exceptions by showing a message box. In my opinion this is the best place to handle exceptions.

By catching exceptions in your own methods for the sole purpose of showing a message box to the user, you're denying any code calling your method of knowing that an exception actually occured and that the method infact failed.

I would only handle an exception if:

  • I need to do some cleanup (like a DB rollback) in which case I would reraise the exception after the cleanup is done.
  • I have some more information to add to the exception.
  • My method can succeed in it's purpose despite the exception.
寄与心 2024-07-19 07:35:21

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

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

(Before I begin: I am a Java guy)
What I recommend:

  1. Find the closest point up the call chain from the exception source where you can handle the exception properly - i.e take corrective measures, signal failure of the transaction/action etc. (Logging by itself should not be considered as handling the exceptions) All the methods between the handler and the thrower should ignore the exception. Prefer unchecked exceptions to checked ones so that the exceptions don't even figure in all those intermediate methods.
  2. Layer boundaries and APIs should specify the exceptions it can throw using checked exceptions since handling those exceptions is part of the contract for the client layer/code that uses it.
  3. Write an exception handler class with a handle(Exception e) method and release that to the team initially and ensure that everyone uses it to handle exceptions. Based on changing exception handling scenarios, keep adding overloaded 'handle' methods later on so that only the handler need to be modified.
  4. Always remember to chain exceptions when doing catch-and-throw. This ensures that the full cause of exception gets reported.
  5. Never log the same exception trace more than once. It makes it very hard to debug using log files.
  6. Top level methods should have a catch clause that will catch any exception that the system may throw. This prevents spilling of our internal information to the outside world if, god forbid, things go wrong in production environment. This is more of a security requirement.
独木成林 2024-07-19 07:35:21

两个位置:

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

Two places:

  • In all event handlers
  • Any location where the catch can do something useful, like supplement the exception with information that will be useful for debugging. Typically a new exception will be created with this information and thrown. Note that the InnerException (or non-.NET equivalent) of this new exception should be set to that of the original exception, in order that things like the stack trace are preserved.
够钟 2024-07-19 07:35:20

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

因此,具有顶级异常处理到位,以您喜欢的方式处理意外异常,然后仅捕获您需要的内容(尽可能接近可能发生的位置)以获得所需的功能。

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

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

Don't catch anything that you are not prepared to and able to handle.

So, have top-level exception handling in place to bomb the application the way you like on unexpected exceptions and then only catch the stuff you need (as close to where it might be occuring) to get the functionality that is needed.

And you should do only one of two things: actually do something to solve/work around the problem or rethrow a more descriptive exception that has the caught exception as its innerException.

EDIT: If you need a finally block (e.g. to release something you allocated in your code) and you don't have anything useful to do with any exceptions that might pop up the same logic applies: simply don't handle them. Instead, use a catch { throw; } to rethrow the exception to a higher level while keeping all exception info intact. (Or simply omit the catch block, which I think/hope does the same thing?)

日记撕了你也走了 2024-07-19 07:35:20

我尝试只捕获那些我可以处理的异常。

我讨厌这样的代码:

      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,我只捕获我可以处理的错误。 当输入不符合我的期望时,我很乐意抛出未捕获的异常。

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

I try to catch ONLY those exceptions that I can deal with.

I HATE code like this:

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

What I especially hate is that what this usually does is to abort the thread anyway, because three lines later there will be an access to i that will assume that i != null.

Then you will read your stacktrace and scroll and scroll and scroll the log til you find the first signifant mistake that made everything else fall apart.

I wish Java didn't force me to catch Exceptions that I cannot deal with, anyway. But what I can do is this:

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

And I declare a lot of "throws" in my function definitions.

I am still dreaming of the day where Eclipse will automatically open a Debugger in the correct line when it will get an uncaught exception. That day, my method will open the correct line.

In other languages, like Smalltalk, I catch only the errors that I can handle. And I happily throw uncaught exceptions when the input does not meet my expectations.

The idea is that I don't want the error to be logged or documented. I want it fixed.

萌辣 2024-07-19 07:35:20

我总是在 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() );
    }
}

I always put a catch in main() as a catch of last resort:

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() );
    }
}
秋凉 2024-07-19 07:35:20

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

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

In C# and Java I prefer to not catch exceptions at all. If I can't avoid it, I rethrow a RunTime-exception immediately.

I'll always use the greediest catch block that has the largest scope needed, but always with the most specific exception-type possible. Since the outcome of the catch block is another throw in 99.99% of the cases, I try to keep the full method within the try block.

北方。的韩爷 2024-07-19 07:35:20

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

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
}

I like to try and keep my exception handling code separate from my other code so I usually create a helper method that does the actual logic and the outer method just deals with exception handling. I've always thought this gives the code a clean look and makes it more readable.

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
}
心凉 2024-07-19 07:35:20

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

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

I like to catch around handlers in the controller that handle events fired from the view. If exceptions give the strong guarantee of safety this is a useful catch point because it is high level enough to report the error and the handlers are usually atomic and related to something that the user has just done so hopefully they'll be able to work out what's going on.

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() );
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文