Java或C#中异常管理的最佳实践

我坚持决定如何处理我的应用程序中的异常。

很多,如果我的异常问题来自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;
}

我认为这种方法没有问题,但我很想知道最佳实践是如何管理异常的(我是否应该在调用堆栈中将异常真正引发出来?)。

总结关键问题:

  • 可以只捕捉异常但不能冒泡或正式通知系统(通过日志或通知给用户)?
  • 对于那些不会导致所有需要try / catch块的异常,有哪些最佳实践?
  • 跟进/编辑

    感谢所有的反馈意见,在线查找异常管理的一些优秀资源:

  • 异常处理的最佳实践| O'Reilly媒体
  • .NET中的异常处理最佳实践
  • 最佳实践:异常管理(文章现在指向archive.org副本)
  • 异常处理反模式
  • 看起来异常管理是基于上下文而变化的事情之一。 但最重要的是,应该如何管理系统中的异常。

    另外还要注意通过过度尝试/捕获代码腐败或不给予例外它的尊重(例外是警告系统,还有什么需要警告?)。

    此外,这是来自m3rLinEz的漂亮选择评论。

    我倾向于同意安德斯海耶斯伯格和你的观点,即如果手术成功或者没有成功,大多数人只会关心。

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

  • 抛出这个异常有什么意义?
  • 处理它有什么意义?
  • 呼叫者真的关心异常情况,还是只关心呼叫是否成功?
  • 是否强迫呼叫者优雅地管理潜在的异常?
  • 你是否尊重这种语言的习惯?
  • 你真的需要返回一个成功的标志,如布尔值吗? 返回boolean(或int)更像是一个C心态,而不是Java(在Java中你只处理异常)。
  • 遵循与语言相关的错误管理结构:)!

  • 对于我来说,想要捕捉异常并将其转换为错误代码似乎很奇怪。 为什么你认为调用者偏好错误代码,而后者在Java和C#中都是默认的?

    至于你的问题:

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

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

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

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

  • 在我的组件和库中,如果我打算处理它或根据它做某件事,我只会捕获一个异常。 或者,如果我想在异常中提供其他上下文信息。
  • 我在应用程序入口点或最高级别使用了一般性尝试。 如果一个异常到达这里,我只是记录它,让它失败。 理想情况下,例外不应该到达这里。
  • 我发现下面的代码是一种气味:

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

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


    我想就这个话题推荐另一个好的来源。 本文分别就C#和Java的发明人Anders Hejlsberg和James Gosling就Java的检查异常进行了访谈。

    失败和例外

    页面底部也有很多资源。

    我倾向于同意安德斯海耶斯伯格和你的观点,即如果手术成功或者没有成功,大多数人只会关心。

    Bill Venners :您提到了关于检查异常的可伸缩性和版本控制问题。 你能否澄清这两个问题的含义?

    Anders Hejlsberg :让我们从版本开始,因为这些问题很容易在那里看到。 假设我创建了一个方法foo,声明它会抛出异常A,B和C.在foo的第二版中,我想添加一些功能,现在foo可能会抛出异常D.这对我来说是一个突破性改变,将D添加到该方法的throws子句中,因为该方法的现有调用者几乎肯定不会处理该异常。

    在新版本中为throws子句添加新的异常会破坏客户端代码。 这就像添加一个方法到接口。 在你发布一个接口之后,它的所有实际用途都是不变的,因为它的任何实现都可能有你想要在下一个版本中添加的方法。 所以你必须改为创建一个新的界面。 与异常类似,您可能必须创建一个名为foo2的全新方法来抛出更多异常,否则您必须在新foo中捕获异常D,并将D转换为A,B或C.

    比尔·威纳斯 :但是,无论如何,你是不是打破了他们的代码,即使是没有检查异常的语言? 如果新版本的foo将抛出一个客户端应该考虑处理的新异常,那么他们的代码是不是因为他们在编写代码时不希望发生异常而被破坏?

    Anders Hejlsberg :不,因为在很多情况下,人们并不在乎。 他们不会处理这些例外情况。 他们的消息循环周围有一个底层异常处理程序。 该处理程序只是提出一个对话框,说明出了什么问题并继续。 程序员通过编写try finally来保护他们的代码,所以如果发生异常,他们会正确地退出,但他们实际上并不想处理异常。

    throws子句,至少是它在Java中实现的方式,并不一定会强制你处理异常,但是如果你不处理它们,它会强制你确认哪些异常可能通过。 它要求你要么捕获声明的异常,要么将它们放在你自己的throws子句中。 要解决这个要求,人们会做出荒谬的事情。 例如,他们用“抛出异常”来装饰每个方法。 这完全破坏了这个功能,你只是让程序员写了更多的gobbledy gunk。 这对任何人都没有帮助。

    编辑:添加更多关于会话的细节

    链接地址: http://www.djcxy.com/p/26611.html

    上一篇: Best practices for exception management in Java or C#

    下一篇: How do I catch a PHP Fatal Error