Java 或 C# 中异常管理的最佳实践 [已关闭]

2022-08-31 09:07:15

我一直在决定如何处理应用程序中的异常。

如果我的异常问题来自1)通过远程服务访问数据或2)反序列化JSON对象,那就太好了。不幸的是,我不能保证这些任务中的任何一个都成功(切断网络连接,格式错误的JSON对象,这是我无法控制的)。

因此,如果我确实遇到异常,我只需在函数中捕获它并向调用方返回FALSE。我的逻辑是,所有呼叫者真正关心的是任务是否成功,而不是为什么它不成功。

下面是一些典型方法的示例代码(在 JAVA 中)

public boolean doSomething(Object p_somthingToDoOn)
{
    boolean result = false;

    try{
        // if dirty object then clean
        doactualStuffOnObject(p_jsonObject);

        //assume success (no exception thrown)
        result = true;
    }
    catch(Exception Ex)
    {
        //don't care about exceptions
        Ex.printStackTrace();
    }
    return result;
}

我认为这种方法很好,但我真的很想知道管理异常的最佳实践是什么(我真的应该在调用堆栈中一直冒泡异常吗?)。

关键问题摘要:

  1. 是否可以只捕获异常,但不冒泡它们或正式通知系统(通过日志或通知用户)?
  2. 对于不会导致所有需要尝试/捕获块的异常,有哪些最佳实践?

跟进/编辑

感谢所有的反馈,在网上找到了一些关于异常管理的优秀资源:

似乎异常管理是根据上下文而变化的事情之一。但最重要的是,在如何管理系统内的异常方面应该保持一致。

此外,还要注意通过过多的尝试/捕获或不尊重异常来破坏代码(异常是警告系统,还需要警告什么?)。

此外,这是m3rLinEz的一个很好的选择评论。

我倾向于同意Anders Hejlsberg和你的观点,即大多数呼叫者只关心操作是否成功。

从这个评论中,它提出了一些在处理异常时需要考虑的问题:

  • 引发此异常的意义何在?
  • 如何处理它?
  • 呼叫者是否真的关心异常,或者他们是否只关心呼叫是否成功?
  • 强制调用方管理潜在异常是否正常?
  • 你是否尊重语言的偶像?
    • 你真的需要返回一个像布尔值这样的成功标志吗?返回布尔值(或int)更像是C思维方式,而不是Java(在Java中,您只会处理异常)。
    • 遵循与:)语言关联的错误管理构造!

答案 1

对我来说,你想捕获异常并将其转换为错误代码似乎很奇怪。为什么你认为调用方更喜欢错误代码而不是异常,而后者在Java和C#中都是默认值?

至于你的问题:

  1. 您应该只捕获可以实际处理的异常。在大多数情况下,仅仅捕获异常并不是正确的做法。有一些例外(例如,线程之间的日志记录和编组异常),但即使对于这些情况,您通常也应该重新抛出异常。
  2. 你的代码中绝对不应该有很多 try/catch 语句。同样,我们的想法是只捕获您可以处理的异常。您可以包含最顶层的异常处理程序,以将任何未处理的异常转换为对最终用户有用的内容,但否则不应尝试在每个可能的位置捕获每个异常。

答案 2

这取决于应用程序和情况。如果构建库组件,则应冒泡异常,尽管应将它们包装为与组件的上下文相关。例如,如果您构建了一个 Xml 数据库,假设您正在使用文件系统来存储数据,并且您正在使用文件系统权限来保护数据。您不希望冒出 FileIOAccessDenied 异常,因为这会泄漏您的实现。相反,您将包装异常并引发 AccessDenied 错误。如果将组件分发给第三方,则尤其如此。

至于是否可以吞下例外。这取决于您的系统。如果您的应用程序可以处理失败情况,并且通知用户失败的原因没有任何好处,那么请继续,尽管我强烈建议您记录失败。我总是发现它被调用来帮助解决问题,并发现他们正在吞噬异常(或者替换它并抛出一个新的而不设置内部异常)。

一般来说,我使用以下规则:

  1. 在我的组件和库中,只有当我打算处理它或基于它做一些事情时,我才会发现异常。或者,如果我想在例外中提供其他上下文信息。
  2. 我在应用程序入口点或尽可能高级别使用常规尝试捕获。如果异常出现,我只是记录它并让它失败。理想情况下,例外情况永远不应该出现在这里。

我发现下面的代码是一种气味:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

像这样的代码没有任何意义,不应该被包括在内。


推荐