何时使用断言以及何时使用异常

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

比如说,

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
}

你能说明一个断言是如何放在这里的吗? 我应该使用一个断言吗?

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

52437 次浏览

我疯了(这个列表可能不完整,而且太长了,不适合写在评论里) ,我想说:

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

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

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

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

总的来说,try/catch 更安全,但是速度稍慢一些,并且必须小心捕捉可能发生的所有类型的错误。所以我会说使用 try/catch-有一天 getGroup 代码可能会改变,而您可能需要更大的网。

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

此外,您还应该阅读 关于断言的 Oracle 文章,以查看更多在何处使用(或不使用)断言的情况。

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

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

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

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

回到微软,建议是在所有公开可用的 API 中抛出异常,并在对内部代码做出的各种假设中使用 Asserts。这是一个有点松散的定义,但我想这取决于每个开发人员的界限。

关于 Exception 的使用,正如其名称所示,它们的使用应该是例外的,因此对于上面提供的代码,如果不存在服务,则 getGroup调用应该返回 null。只有在网络链路出现故障或类似情况时才会发生异常。

我猜想结论是,每个应用程序都需要由开发团队来定义断言和异常的边界。

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

所以在 Java 中使用断言

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

遗憾的是,可以禁用断言。在生产环境中,当跟踪不可预见的事情时,您需要所有可以获得的帮助,因此断言本身不合格。

一般来说:

  • 使用断言进行内部一致性检查,如果有人关闭断言,那么这种检查根本无关紧要。(注意,默认情况下 java命令关闭所有断言。)
  • 使用常规测试进行任何类型的检查,哪些不应该被关闭。这个 包括防御性检查可以防止 bug 以及用户或外部服务提供的任何验证数据/请求/任何东西造成的潜在损害。

下面的代码来自您的问题是坏样式 还有潜在的错误

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(特别是不记录它) ,您将使问题更难诊断/调试,并可能允许应用程序造成更大的损害。

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

请参阅 Sun 文档的6.1.2部分(断言与其他错误代码)。

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

这篇文章给出了我所见过的关于何时使用断言的最佳建议:

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

根据这个文档 http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general,“断言语句适用于非公共前提条件、后置条件和类不变量检查。公共先决条件检查仍然应该通过检查方法内部来执行,这些方法会导致特定的、记录在案的异常,例如 IllegalArgumentException 和 IllegalStateException。”

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