我以标准的方式在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
}
我的推理是否正确?
其他差异/用例/最佳实践/限制是什么?
两种方法?
关于在AssertionError中提供描述 - 是应该提供还是仅仅是Error(和
断言类型)足以或多或少地确定堆栈跟踪
如果发现错误,将提供?
你的断言多久经常变慢?我个人喜欢在现实世界中驾驶时保持安全带,而不仅仅是在学习时:)(事实上,在生产代码中比在测试代码中快速失败更重要 - 如果你继续到达一个无效的状态,你可能会擦除真实的生产数据。)当你有证据证明它们以一种显着的方式减慢你的程序时,只考虑删除断言。
基本上你是对的。虽然有些人希望从生产代码中删除断言,因为无效行为被认为比直接应用程序失败更好。使用AssertionError提供至少一个基本错误描述可能是一个好主意,这样就可以在不必挖掘源文件的情况下完成第一级调试(如果某些bozo只报告错误消息,没有堆栈跟踪)。
@JonSkeet但你可以在代码的那一部分留下断言。使用AssertionError你没有任何选项,即使故意禁用了断言,它也会被抛出。
@HotLicks您也可以使用assert false"Should not be reached"给出原因代码,这样就不会区分assert false和throw AssertionError()。
根据Java技术说明"使用断言编程",如果getFoo可公开访问,则您的示例无效
如果我可以对java进行重大更改,那么Throwable的构造函数和所有错误都将是包私有的。然后我们不会进行这种对话。
在技??术说明"使用断言编程:控制流不变量"中,给出了以下代码:
void foo() {
for (...) {
if (...)
return;
}
assert false; // Execution should never reach this point!
}
但是也给出了以下注释:
Note: Use this technique with discretion. If a statement is unreachable as defined in the Java Language Specification, you will get a compile time error if you try to assert that it is not reached. Again, an acceptable alternative is simply to throw an AssertionError.
断言关闭时,您可能不会指望抛出AssertionError。由于AssertionError构造函数是公共的,并且因为可能没有替换AssertionError(String message, Throwable cause),我猜你应该期望它们即使它们被关闭了。
如Jon Skeet建议的那样,在无法访问的代码上抛出AssertionError(即没有任何真正的表达式进行评估)将永远不会减慢代码速度,因此在性能方面不会受到影响。
所以最后抛出AssertionError似乎没问题。
生成赏金后才发现评论,当然欢迎其他答案。
我认为比AssertionError更具描述性的异常类名是CoderMalfunctionError。 唉,指的是字符集编码器而不是键盘前的编码器!;-)
我建议不要直接抛出AssertionError。如果你选择依靠AssertionError来检查不变量,前/后条件,状态条件等,你最好还是使用常规断言,并在生产中打开"-ea"标志。
原因是断言机制(除了在编译器级别进行优化)使您有机会立即打开或关闭所有断言。即使您现在无法想到这样做的理由,如果您在将来遇到某个原因,只需考虑您必须查看所有throw new AssertionError(...)类型代码并用令人讨厌的条款。你得到了照片。
正如您不希望在代码中的许多位置硬编码的幻数,并且可能使用常量,您不应该感染您的代码有很多重复(即throw new AssertionError(...)部分)。
关于断言的另一个词虽然。我相信在依赖生产代码中的断言错误之前,您应该三思而后行。原因是AssertionError非常通用。它有一个信息和一个原因,但这就是它。
相反,请考虑使用特定的RuntimeException子类,这些子类将通过与问题更相关的特定类以及携带与问题相关的实际数据来传达更多信息。
举个简单的例子,考虑一下您在问题中提到的案例,其中有一部分代码是您不希望达到的。断言或AssertionError会传达一个事实,即你达到了一些意想不到的代码,但不是更多。使用特定的RuntimeException还可以在该时间点传递方法的局部变量和参数的状态。您可以认为这可以通过设置断言消息或AssertionError来包含此信息,但在使用自动错误记录/处理机制时这不起作用。这些机制可以使用您用于检查意外行为的RuntimeException的不同子类上的访问者模式来处理意外行为(通过句柄我还意味着快速失败,不一定是恢复)。
我在很大程度上同意你的评估(可能比我给出的答案更多),但我写的答案来自Sun / Oracle文档。 所以我只能得出结论,根据Technote,它是可以的,如果它不被允许,构造函数应该被隐藏。 除此之外,在assert false和new Error之间选择无法访问的代码(其中第一个不被视为退出点)是在两个邪恶之间进行选择。 我同意你的看法,错误是错误的,但是必须使用return null或类似错误同样糟糕。