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