【问题标题】:When to use an assertion and when to use an exception何时使用断言以及何时使用异常
【发布时间】:2010-12-29 18:46:37
【问题描述】:

大多数时候我会使用异常来检查代码中的条件,我想知道什么时候是使用断言的合适时机?

例如,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

您能否指出一个断言如何适合这里?我应该使用断言吗?

似乎我从不在生产代码中使用断言,只在单元测试中看到断言。我知道在大多数情况下,我可以使用异常来进行上述检查,但我想知道“专业”的适当方法。

【问题讨论】:

    标签: java exception assertion


    【解决方案1】:

    出于我的想法(列表可能不完整,并且太长,无法放入评论),我会说:

    • 检查传递给公共或受保护方法和构造函数的参数时使用异常
    • 在与用户交互或希望客户端代码从异常情况中恢复时使用异常
    • 使用异常来解决可能发生的问题
    • 在检查私有/内部代码的前置条件、后置条件和不变量时使用断言
    • 使用断言向您自己或您的开发团队提供反馈
    • 在检查不太可能发生的事情时使用断言,否则意味着您的应用程序中存在严重缺陷
    • 使用断言来陈述您(假定)知道是真实的事情

    换句话说,异常处理应用程序的健壮性,而断言处理其正确性。

    断言被设计成写起来很便宜,你几乎可以在任何地方使用它们,我正在使用这个经验法则:断言语句看起来越愚蠢,它就越有价值并且它嵌入的信息越多。当调试一个行为不正确的程序时,你肯定会根据你的经验检查更明显的失败可能性。然后您将检查不可能发生的问题:这正是断言有很大帮助并节省时间的时候。

    【讨论】:

    【解决方案2】:

    应该使用断言来检查不应该发生的事情,而应该使用异常来检查可能发生的事情。

    例如,一个函数可能除以 0,因此应该使用异常,但可以使用断言来检查硬盘驱动器是否突然消失。

    断言会阻止程序运行,但异常会让程序继续运行。

    请注意,if(group != null) 不是断言,它只是一个条件。

    【讨论】:

    • “一个断言可以用来检查硬盘是否突然消失” - 我想说这是不正确的:为什么你希望在开发过程中处理这个,而不是在生产中(当断言通常是禁用)?
    • 关于硬盘的评论有误。断言用于检查代码逻辑中的错误。永远不要用它们来检查你无法控制的东西。请记住,如果断言失败,则意味着您的代码错误
    • @Marius 您的条件可以用这样的断言替换:assert group != null
    • 否决,因为硬盘驱动器示例与您自己的理念相矛盾。硬盘“消失”(从代码的角度来看)实际上可能在现实中发生——无论多么不可能。就像@IanGoldby 所说,断言应该完全依赖于你的代码控制的东西。
    • 如果 Gregory Pakosz 发布了更好的答案,请阅读该帖子。
    【解决方案3】:

    请记住,可以在运行时使用参数和are disabled by default 禁用断言,因此除了调试目的之外不要指望它们。

    您还应该阅读Oracle article about assert 以了解更多使用 - 或不使用 - 断言的情况。

    【讨论】:

    • Hue hue hue 我想知道为什么我的代码在 Eclipse 中失败但在命令行上运行良好。
    【解决方案4】:

    作为一般规则:

    • 使用断言进行内部一致性检查,如果有人将其关闭则根本不重要。 (注意java 命令默认关闭所有断言。)
    • 使用常规测试进行任何不应该关闭的检查。这包括防御性检查,以防止由错误和任何验证数据/请求/用户或外部服务提供的任何内容造成的潜在损害。

    您问题中的以下代码样式不好并且可能有错误

    try {
        group = service().getGroup("abc");
    } catch (Exception e) {
        //i dont log error because i know whenever error occur mean group not found
    }
    

    问题是您不知道异常意味着未找到该组。 service() 调用也有可能引发了异常,或者它返回了 null,然后导致了 NullPointerException

    当您捕获“预期”异常时,您应该只捕获您预期的异常。通过捕获java.lang.Exception(尤其是不记录它),您会更难诊断/调试问题,并可能让应用程序造成更多损害。

    【讨论】:

      【解决方案5】:

      嗯,回到 Microsoft,建议是在您公开提供的所有 API 中抛出异常,并在您对内部代码做出的各种假设中使用断言。这是一个有点松散的定义,但我想每个开发人员都可以划清界限。

      关于异常的使用,顾名思义,它们的使用应该是异常的,因此对于您上面提供的代码,如果不存在服务,getGroup 调用应该返回null。只有在网络链接出现故障或类似情况时才会出现异常。

      我想结论是,对于每个应用程序来说,定义断言与异常的边界有点留给开发团队。

      【讨论】:

      • 恕我直言,这种建议的问题在于,只要 API 的公共部分和私有部分之间的边界非常固定,它就可以了。如果您正在开发新代码,那么这个边界通常是非常流畅的......
      • 是的,你是对的。这是一个指导方针,但归根结底,它留给了程序员的敏感性。我认为这些没有最终的定义线,所以我猜你只是通过阅读大量不同的代码来选择你认为正确的东西。
      【解决方案6】:

      根据该文档http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general,“断言语句适用于非公共前置条件、后置条件和类不变检查。公共前置条件检查仍应通过导致特别记录的异常的方法内部的检查来执行,例如 IllegalArgumentException 和IllegalStateException。”

      如果您想了解有关前置条件、后置条件和类不变量的更多信息,请查看此文档:http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions。它还包含断言用法示例。

      【讨论】:

        【解决方案7】:

        测试 null 只会捕获导致问题的 null,而您拥有的 try/catch 将捕获 any 错误。

        一般来说,try/catch 更安全,但速度稍慢,而且您必须小心捕捉所有可能发生的错误。所以我会说使用 try/catch - 有一天 getGroup 代码可能会改变,而你可能需要更大的网络。

        【讨论】:

          【解决方案8】:

          您可以在使用它们时牢记这个简单的区别。异常将用于检查预期的和意外的错误,称为已检查和未检查的错误,而断言主要用于在运行时进行调试,以查看假设是否得到验证。

          【讨论】:

            【解决方案9】:

            不幸的是,断言可以被禁用。在生产过程中,您需要在追踪无法预料的事情时获得所有帮助,因此断言会取消自己的资格。

            【讨论】:

              【解决方案10】:

              我承认我对你的问题有点困惑。当不满足断言条件时,将引发异常。令人困惑的是,这被称为AssertionError。请注意,它是未选中的,例如(例如)IllegalArgumentException,它在非常相似的情况下被抛出。

              所以在 Java 中使用断言

              1. 是一种更简洁的编写条件/抛出块的方法
              2. 允许您通过 JVM 参数打开/关闭这些检查。通常我会一直打开这些检查,除非它们影响运行时性能或有类似的惩罚。

              【讨论】:

              • AssertionError 是 Error 而不是 RuntimeException 的子类。
              • 啊。当然。我在考虑选中/未选中。现已更正
              • 它解释了断言是什么(从一个有争议的角度),但没有解释何时准确地使用它们。
              【解决方案11】:

              请参阅以下链接中 Sun 文档的第 6.1.2 节(断言与其他错误代码)。

              http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

              本文档提供了我所见过的关于何时使用断言的最佳建议。引用文档:

              “一个好的经验法则是,您应该对您想忘记的异常情况使用断言。断言是处理和忘记您不期望的条件或状态的最快方法不得不处理。”

              【讨论】:

                猜你喜欢
                • 2021-04-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-10-25
                • 2017-12-14
                • 1970-01-01
                • 2011-05-29
                • 1970-01-01
                相关资源
                最近更新 更多