使用断言的一些(反)模式(Java等)
最后,我有一个关于Stack Overflow的问题要问!:-)
主要目标是Java,但我相信它主要是与语言无关的:如果你没有原生断言,你可以随时模拟它。
我为一家公司工作,该公司销售一套用Java编写的软件。代码很旧,至少可以追溯到Java 1.3,在某些地方,它显示...这是一个很大的代码库,大约200万行,所以我们不能一次重构它。
最近,我们将最新版本从 Java 1.4 语法和 JVM 切换到 Java 1.6,保守地使用了一些新功能,例如(我们曾经使用过 DEBUG。ASSERT宏 - 我知道在1.4中已经引入,但我们以前没有使用它),泛型(只有类型化集合),foreach循环,枚举等。assert
assert
我对断言的使用仍然有点绿色,尽管我已经阅读了几篇关于这个主题的文章。然而,我看到的一些用法让我感到困惑,伤害了我的常识......^_^所以我想我应该问一些问题,看看我想要纠正东西是否正确,或者它是否违背了惯例。我很冗长,所以我加粗了问题,对于那些喜欢略读的东西。
作为参考,我在SO中搜索了断言java,发现了一些有趣的线程,但显然没有确切的重复。
-
如何避免Java中的“!= null”语句? 和多少空值检查就足够了?是非常相关的,因为很多断言我们刚刚检查变量是否为空。在我们的代码中的某些地方,有空对象的用法(例如,返回),但并非总是如此。我们必须忍受这一点,至少对于遗留代码的维护而言。
new String[0]
- Java断言中也有一些好的答案没有得到充分利用。
- 哦,SO有理由指出我什么时候应该使用Debug.Assert()?问题也是相关的(减少重复的好功能!
首先,引发我今天问题的主要问题:
SubDocument aSubDoc = documents.GetAt( i );
assert( aSubDoc != null );
if ( aSubDoc.GetType() == GIS_DOC )
{
continue;
}
assert( aSubDoc.GetDoc() != null );
ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();
(是的,我们使用MS的C / C++样式/代码约定。我甚至喜欢它(来自相同的背景)!所以起诉我们。
首先,形式来自呼叫的转换。我不喜欢多余的括号,因为assert是一种语言结构,而不是(这里不再是)函数调用。我也不喜欢:-)
接下来,断言不在这里测试不变量,而是用作防止不良值的防范措施。但据我所知,它们在这里是无用的:断言将引发异常,甚至没有用伴随字符串记录,并且只有在启用断言时。因此,如果我们有选择,我们只需要一个抛出的断言,而不是常规的NullPointerException。这看起来并不是一个最重要的优势,因为我们无论如何都会在最高级别捕获不受控制的异常。
我假设我们可以摆脱它们并忍受它(即让Java提出这种未被忽略的异常)是对的吗?(或者,当然,如果可能的话,测试空值,这是在其他地方完成的)。assert()
DEBUG.ASSERT()
return (foo);
-ea
旁注:如果我必须在上面的片段中断言,我会针对ci值而不是getter这样做:即使大多数getter都是优化/内联的,我们也不能确定,所以我们应该避免调用它两次。
有人在最后引用的线程中告诉公共方法应该使用针对参数值的测试(公共API的使用),私有方法应该依赖于断言。好的建议。
现在,这两种方法都必须检查另一个数据源:外部输入。即。例如,来自用户、数据库、某些文件或网络的数据。
在我们的代码中,我看到针对这些值的断言。我总是将这些更改为实际测试,因此即使禁用断言,它们也会起作用:这些不是不变的,必须正确处理。
我只看到一个可能的异常,其中输入应该是常量,例如,一个数据库表充满了关系中使用的常量:如果这个表被更改但相应的代码没有更新,程序就会中断。
您是否看到其他例外情况?
我看到的另一个相对频繁的使用,这似乎是可以的:在开关的默认值中,或者在一系列测试结束时所有可能的值(这些情况可以追溯到我们使用枚举之前!),对我来说通常有一个
看起来合法的(这些情况不应该在生产中发生),你怎么看?(除了“没有开关, 使用OO“建议,这些建议在这里无关紧要)。else if
assert false : "Unexpected value for stuff: " + stuff;
最后,我在这里错过了任何其他有用的用例或烦人的陷阱吗?(可能!