在java中使用AssertionError和断言

dev*_*ull 13 java exception-handling assertions

我以标准的方式在Java中使用断言,在我的IDE中打开它们.所以他们不是生产发布的一部分.最近我一直在看代码示例,throw new AssertionError()我开始考虑AssertionError应该使用的情况而不是断言.

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

因为AssertionError,恰恰相反.

我还发现AssertionError在执行不应该得到的代码中更实用,而不是使用assert false //We should not be here.特别是如果需要返回值.例如:

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
}
Run Code Online (Sandbox Code Playgroud)
  • 我的推理是否正确?
  • 这两种方法的其他差异/用例/最佳实践/限制是什么?
  • 关于提供描述AssertionError- 应该提供还是仅仅是Error(和断言类型)的事实足以或多或少地确定在发现错误的情况下将提供堆栈跟踪?

Maa*_*wes 7

在技​​术说明"使用断言编程:控制流不变量"中,给出了以下代码:

void foo() {
    for (...) {
      if (...)
        return;
    }
    assert false; // Execution should never reach this point!
}
Run Code Online (Sandbox Code Playgroud)

但是也给出了以下注释:

注意:谨慎使用此技术.如果Java语言规范中定义的语句无法访问,如果您尝试断言未到达,则会出现编译时错误.同样,一个可接受的替代方案就是抛出AssertionError.


AssertionError断言关闭时,您可能不会指望抛出.由于AssertionError构造函数是公开的,并且由于可能没有替换AssertionError(String message, Throwable cause),我猜你即使它们被关闭也应该期待它们.


投掷一个AssertionError无法访问的代码(即没有任何真正的表达式进行评估)将永远不会减慢代码,正如Jon Skeet建议的那样,因此在性能方面不会受到影响.


所以最后投掷AssertionError似乎没问题.


eth*_*far 6

我建议不要AssertionError直接投掷.如果你选择依靠AssertionErrors来检查不变量,前/后条件,状态条件等,你最好还是使用常规断言,同时在生产中打开"-ea"标志.
原因是断言机制(除了在编译器级别进行优化)使您有机会立即打开或关闭所有断言.即使您现在无法想到这样做的理由,如果您在将来遇到某个原因,只需考虑您必须查看所有throw new AssertionError(...)类型代码并用一个讨厌的if条款包围它.你得到了照片.
就像你不希望在代码中的许多地方硬编码的幻数,并且可能会使用常量,你不应该感染你的代码有很多重复(即throw new AssertionError(...)部分).

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