在java中使用AssertionError和断言

在java中使用AssertionError和断言,java,exception-handling,assertions,Java,Exception Handling,Assertions,我以标准方式在Java中使用断言,在IDE中打开它们。因此,它们不是产品发布的一部分。最近,我看到了带有抛出新断言错误()的代码示例,我开始思考应该使用AssertionError而不是断言的情况 我的猜测是,主要的区别在于断言的可选性,因此它们不会降低生产性能,因此它们可能会经常出现在代码中,但修复用户报告的几乎不可重复的错误更难 对于断言错误,情况正好相反 我还发现AssertionError在代码中不应该执行的地方更实用,而不是使用assertfalse//我们不应该在这里。特别是当需要返

我以标准方式在Java中使用断言,在IDE中打开它们。因此,它们不是产品发布的一部分。最近,我看到了带有
抛出新断言错误()的代码示例,我开始思考应该使用
AssertionError
而不是断言的情况

我的猜测是,主要的区别在于断言的可选性,因此它们不会降低生产性能,因此它们可能会经常出现在代码中,但修复用户报告的几乎不可重复的错误更难

对于断言错误
,情况正好相反

我还发现
AssertionError
在代码中不应该执行的地方更实用,而不是使用
assertfalse//我们不应该在这里
。特别是当需要返回值时。例如:

int getFoo(AnEnum a){
    if (a == AnEnum.ONE)
       return bar();
    else if (a == AnEnum.TWO)
       return SOME_VALUE;
    //else
    assert false; //throw new AssertionError();
    return -1; //not necessary when usin AssertionError
}
  • 我的推理正确吗
  • 其他区别/用例/最佳实践/限制是什么 这两种方法中的哪一种
  • 关于在
    断言错误
    中提供描述,是否应该提供描述,或者仅仅是因为它是
    错误
    (以及 (断言类型)足以或多或少地确定堆栈跟踪 如果发现bug,是否会提供
技术说明中给出了以下代码:

void foo() {
    for (...) {
      if (...)
        return;
    }
    assert false; // Execution should never reach this point!
}
但也给出了以下注释:

注意:谨慎使用此技巧。如果一条语句如Java语言规范中所定义的那样不可访问,那么如果您试图断言未访问该语句,就会出现编译时错误。同样,一个可接受的替代方法是抛出断言错误


当断言关闭时,您可能不希望抛出
AssertionError
。由于
AssertionError
构造函数是公共的,而且可能没有替代
AssertionError(字符串消息,可丢弃原因)
,因此我想即使关闭它们,您也应该期待它们


正如Jon Skeet所建议的那样,在不可访问的代码(即没有任何要计算的实际表达式)上抛出一个
AssertionError
,将永远不会减慢代码的速度,因此不会影响性能



所以最后抛出
AssertionError
似乎没问题。

我建议不要直接抛出
AssertionError
s。如果您选择依赖于
AssertionError
s来检查不变量、前置/后置条件、状态条件等,您最好还是在生产中使用启用“-ea”标志的常规断言。
原因是断言机制(而不是在编译器级别进行优化)使您有机会一次打开或关闭所有断言。即使你现在想不出这样做的理由,如果你在将来遇到一个原因,只要考虑一下你的所有<代码>扔掉新的断言错误(…)<代码>类型代码,然后用一个讨厌的<代码>包围它,如果子句。你明白了。
正如您不希望将一个神奇的数字硬编码到代码中的许多地方,并且可能会使用一个常量,您也不应该用许多重复来感染代码(即
抛出新的断言错误(…)
部分)

关于断言的另一个词。我认为,在依赖生产代码中的断言错误之前,您应该三思。原因是,
AssertionError
非常通用。它有一个信息和原因,但基本上就是这样。
考虑使用特定的<代码> RunTimeExt< /Cord>子类,这两个子类将通过与一个与问题相关的特定类来传递更多信息,以及携带与问题相关的实际数据。
作为一个简单的例子,考虑一个你在你的问题中提到的代码,其中有部分代码是你不希望达到的。断言或
AssertionError
会传达这样一个事实:您获得了一些意外的代码,但不会更多。使用特定的
RuntimeException
还可以在该时间点传递局部变量和方法参数的状态。您可以认为,通过设置断言消息或
AssertionError
来包含此信息是可行的,但在使用自动错误记录/处理机制时,这不起作用。这些机制可以使用
RuntimeException
的不同子类上的访问者模式来处理意外行为,您正在使用该模式来检查意外行为(我所说的句柄也指快速失败,不一定是恢复)。

您的断言实际上有多慢?就我个人而言,我喜欢在现实世界中开车时系好安全带,而不仅仅是在学习时:)(事实上,在生产代码中快速失败要比在测试代码中失败重要得多——如果你一直处于无效状态,你很可能会擦除真实的生产数据。)当你有证据表明他们正在以一种重要的方式减慢你的程序时,只考虑删除断言。基本上你是正确的。尽管有些人希望从生产代码中删除断言,因为无效行为被视为比彻底的应用程序失败要好。对于AssertionError,至少提供一个基本的错误描述可能是一个好主意,这样可以在不必深入源文件的情况下完成一级调试(如果某些bozo只报告错误消息,而没有堆栈跟踪)。@JonSkeet,但您可以对这部分代码保留断言。使用
AssertionError
时,您没有任何选项,即使已故意禁用断言,也会抛出该选项。@HotLicks您可以使用
AssertionError“不应到达”给出原因代码,这样就不会区分
AssertionError
throw AssertionError()
。您的示例如下: