130

大多数时候我会使用异常来检查代码中的条件,我想知道什么时候使用断言合适?

例如,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

你能指出一个断言如何适合这里吗?我应该使用断言吗?

似乎我从不在生产代码中使用断言,只在单元测试中看到断言。我知道在大多数情况下,我可以使用异常来进行上述检查,但我想知道“专业”的适当方法。

4

11 回答 11

179

出于我的考虑(列表可能不完整,并且太长而无法放入评论),我会说:

  • 检查传递给公共或受保护方法和构造函数的参数时使用异常
  • 在与用户交互或期望客户端代码从异常情况中恢复时使用异常
  • 使用异常来解决可能发生的问题
  • 在检查私有/内部代码的前置条件、后置条件和不变量时使用断言
  • 使用断言向您自己或您的开发团队提供反馈
  • 在检查不太可能发生的事情时使用断言,否则这意味着您的应用程序中存在严重缺陷
  • 使用断言来陈述你(假设)知道是真的事情

换句话说,异常处理应用程序的健壮性,而断言处理其正确性。

断言被设计成写起来很便宜,你几乎可以在任何地方使用它们,我正在使用这个经验法则:断言语句看起来越愚蠢,它就越有价值并且它嵌入的信息越多。当调试一个行为不正确的程序时,你肯定会根据你的经验检查更明显的失败可能性。然后您将检查不可能发生的问题:这正是断言有很大帮助并节省时间的时候。

于 2009-12-24T10:03:20.367 回答
88

断言应该用于检查不应该发生的事情,而异常应该用于检查可能发生的事情。

例如,一个函数可能除以 0,因此应该使用异常,但可以使用断言来检查硬盘驱动器是否突然消失。

断言会阻止程序运行,但异常会让程序继续运行。

请注意,这if(group != null)不是一个断言,这只是一个条件。

于 2009-12-24T10:05:13.707 回答
28

请记住,断言可以在运行时使用参数禁用,并且默认情况下是禁用的,所以除了调试目的之外不要指望它们。

您还应该阅读有关断言的 Oracle 文章,以了解更多使用或不使用断言的情况。

于 2009-12-24T10:04:49.137 回答
16

作为基本规则:

  • 使用断言进行内部一致性检查,如果有人将它们关闭则根本不重要。(请注意,该java命令默认关闭所有断言。)
  • 对任何不应该关闭的检查使用常规测试。这包括防御性检查,以防止错误造成的潜在损害,以及任何验证数据/请求/用户或外部服务提供的任何内容。

您问题中的以下代码风格不好可能有问题

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

问题是您不知道异常意味着未找到该组。调用也有可能service()引发异常,或者它返回null然后导致NullPointerException.

当你捕获一个“预期的”异常时,你应该捕获你期望的异常。通过捕获java.lang.Exception(尤其是不记录它),您使诊断/调试问题变得更加困难,并可能让应用程序造成更大的损害。

于 2009-12-24T14:50:54.770 回答
4

好吧,回到微软,建议是在您公开提供的所有 API 中抛出异常,并在您对内部代码做出的各种假设中使用断言。这是一个有点松散的定义,但我想每个开发人员都可以划清界限。

关于异常的使用,顾名思义,它们的使用应该是异常的,因此对于您上面提供的代码,如果不存在服务,getGroup调用应该返回。null仅当网络链接出现故障或类似情况时才会发生异常。

我想结论是,对于每个应用程序来说,定义断言与异常的边界有点留给开发团队。

于 2009-12-24T10:06:30.447 回答
3

根据此文档http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general,“断言语句适用于非公共前置条件、后置条件和类不变量“

如果您想了解有关前置条件、后置条件和类不变量的更多信息,请查看此文档:http ://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions 。它还包含断言用法的示例。

于 2012-10-22T21:31:03.013 回答
1

对 null 的测试只会捕获导致问题的 null,而您拥有的 try/catch 将捕获任何错误。

从广义上讲,try/catch 更安全,但速度稍慢,并且您必须小心捕获所有可能发生的错误。所以我会说使用 try/catch - 有一天 getGroup 代码可能会改变,而你可能需要更大的网络。

于 2009-12-24T10:04:13.070 回答
1

我承认我对你的问题有点困惑。当不满足断言条件时,将引发异常。令人困惑的是,这被称为AssertionError。请注意,它是未经检查的,例如(例如)在非常相似的情况下抛出的IllegalArgumentException 。

所以在Java中使用断言

  1. 是编写条件/抛出块的更简洁的方法
  2. 允许您通过 JVM 参数打开/关闭这些检查。通常我会一直保留这些检查,除非它们影响运行时性能或有类似的惩罚。
于 2009-12-24T10:41:36.677 回答
1

不幸的是,断言可以被禁用。在生产中,您需要在追踪不可预见的事情时获得的所有帮助,因此断言会取消自己的资格。

于 2009-12-24T14:25:42.777 回答
1

您可以在使用它们的同时牢记这个简单的区别。异常将用于检查预期的和意外的错误,称为已检查和未检查的错误,而断言主要用于在运行时进行调试,以查看假设是否得到验证。

于 2012-06-11T09:37:26.817 回答
0

请参阅以下链接中 Sun 文档的第 6.1.2 节(断言与其他错误代码)。

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

本文档提供了我所见过的关于何时使用断言的最佳建议。引用文档:

“一个好的经验法则是,你应该对你想忘记的异常情况使用断言。断言是处理和忘记你不希望必须的条件或状态的最快方法处理。”

于 2012-07-12T04:35:44.683 回答