Phi*_*Lho 14 java language-agnostic assert
最后,我有一个问题要问Stack Overflow!:-)
主要目标是Java,但我认为它主要与语言无关:如果你没有本机断言,你可以随时模拟它.
我在一家销售一套用Java编写的软件的公司工作.代码很旧,至少可以追溯到Java 1.3,在某些地方,它显示......这是一个庞大的代码库,大约有两百万行,所以我们不能一次重构它.
最近,我们将最新版本从Java 1.4语法和JVM切换到Java 1.6,保守地使用了一些新功能,例如assert(我们曾经使用过DEBUG.ASSERT宏 - 我知道assert已经在1.4中引入但我们没有使用过它之前),泛型(只有打字的集合),foreach循环,枚举等.
尽管我已经阅读了几篇关于这个主题的文章,但我对assert的使用仍然有点青睐.然而,我看到的一些用法让我感到困惑,伤害了我的常识... ^ _ ^所以我想我应该问一些问题,看看我是否正确想要纠正的东西,或者它是否违背了常规做法.我很啰嗦,所以我大胆地提出问题,因为那些喜欢撇去东西的人.
作为参考,我在SO中搜索断言java并发现了一些有趣的线程,但显然没有完全重复.
new String[0])但并非总是如此.我们必须忍受这一点,至少是为了维护遗留代码.首先,主要问题,今天引发了我的问题:
SubDocument aSubDoc = documents.GetAt( i );
assert( aSubDoc != null );
if ( aSubDoc.GetType() == GIS_DOC )
{
continue;
}
assert( aSubDoc.GetDoc() != null );
ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();
Run Code Online (Sandbox Code Playgroud)
(是的,我们使用MS的C/C++样式/代码约定.我甚至喜欢它(来自相同的背景)!所以起诉我们.)
首先,assert()表单来自DEBUG.ASSERT()调用的转换.我不喜欢额外的括号,因为assert是一个语言结构,而不是(不再是,这里)一个函数调用.我也不喜欢return (foo);:-)
接下来,断言不在这里测试不变量,它们更像是用来防止坏值.但正如我所理解的那样,它们在这里没用:assert会抛出一个异常,甚至没有记录伴随字符串,只有在断言被启用时才会抛出异常.所以,如果我们有-ea选项,我们只是抛出一个断言而不是常规的NullPointerException.这看起来不是最重要的优势,因为无论如何我们都会在最高级别捕获未经检查的异常.
我是否正确地假设我们可以摆脱它们并与之共存(即让Java引发这种无法解决的异常)?(或者,当然,如果可能的话,测试空值,这在其他地方进行).
旁注:我应该在上面的片段中断言,我会针对ci值,而不是针对getter:即使大多数getter都经过优化/内联,我们也无法确定,所以我们应该避免调用它两次.
有人告诉我,在最后引用的线程中,公共方法应该使用针对参数值的测试(公共API的使用),而私有方法应该依赖于断言.好建议.
现在,这两种方法都必须检查另一个数据源:外部输入.IE浏览器.例如,来自用户,来自数据库,来自某个文件或来自网络的数据.
在我们的代码中,我看到了针对这些值的断言.我总是将这些更改为真正的测试,因此即使禁用断言它们也会起作用:这些不是不变量,必须正确处理.
我只看到一个可能的异常,其中输入应该是常量,例如填充了关系中使用的常量的数据库表:如果更改此表但相应的代码未更新,则程序将中断.
你看到其他例外吗?
我看到的另一个相对频繁的用法,似乎没问题:在交换机的默认情况下,或者在一系列else if测试结束时 所有可能的值(这些情况可以追溯到我们使用枚举之前!),通常有一个assert false : "Unexpected value for stuff: " + stuff;
看似合法的我(这些情况不应该在生产中发生),你怎么看?(超出"无开关,使用OO"这些与此无关的建议).
最后,还有其他有用的用例或我在这里错过的讨厌的陷阱吗?(大概!)
最重要的规则是避免断言中的副作用.换句话说,代码应该与关闭断言的行为完全相同,因为断言打开时并没有失败(显然失败的断言会改变行为,因为它们会引发错误).
第二条规则是不使用断言进行基本检查.它们可以关闭(或者更准确地说,不能打开).对于非私有方法的参数检查,请使用IllegalArgumentException.
断言是可执行的假设.我使用断言表明我对该程序当前状态的看法.例如,像"我假设n在这里是正面的"或"我假设列表恰好有一个元素在这里"之类的东西.
小智 2
您已经谈到了我认为一般应该避免断言的许多原因。除非您使用的代码库中断言的使用有非常严格的指导方针,否则您很快就会陷入无法关闭断言的情况,在这种情况下,您可能只使用正常的逻辑测试。
所以,我的建议是跳过断言。不要坚持额外的空指针检查,语言会为你做这件事。但是,如果指针可能暂时不会被取消引用,则预先进行空检查是一个好主意。另外,对于“永远”不应该发生的情况(最后的 if 分支或默认 switch 情况),始终使用真正的异常,不要使用“assert false”。如果你使用断言,有人可能会关闭它,如果这种情况真的发生,事情会变得非常混乱。
| 归档时间: |
|
| 查看次数: |
4742 次 |
| 最近记录: |