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

时间:2009-12-24 10:00:44

标签: java exception assertion

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

例如,

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
}

你能指出断言是如何适应这里的吗?我应该使用断言吗?

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

11 个答案:

答案 0 :(得分:160)

在我的脑海里(列表可能不完整,而且评论太长而无法填写),我会说:

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

换句话说,异常解决了应用程序的健壮性,而断言解决了它的正确性。

断言的编写成本很低,几乎可以在任何地方使用它们而且我使用这个经验法则:断言语句看起来越愚蠢,它越有价值,嵌入的信息就越多。在调试不正常的程序时,您一定会根据您的经验检查更明显的故障可能性。然后你将检查那些不可能发生的问题:这正是断言有助于节省时间的时候。

答案 1 :(得分:78)

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

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

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

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

答案 2 :(得分:25)

请记住,可以在运行时使用参数和are disabled by default禁用断言,因此除了调试目的外,不要依赖它们。

此外,您应该阅读Oracle article about assert以查看更多使用或不使用的案例 - 断言。

答案 3 :(得分:15)

作为一般规则:

  • 使用断言进行内部一致性检查,如果有人将其关闭则根本不重要。 (请注意,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(特别是不记录它),您将更难以诊断/调试问题,并可能允许应用程序造成更多损害。

答案 4 :(得分:3)

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

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

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

答案 5 :(得分:3)

根据此文档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。它还包含断言用法的示例。

答案 6 :(得分:1)

测试null只会捕获导致问题的空值,而try / catch就会捕获任何错误。

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

答案 7 :(得分:1)

我承认我对你的问题感到有些困惑。如果不满足断言条件,则抛出异常。令人困惑的是,这被称为AssertionError。请注意,它是未经检查的,例如(例如)IllegalArgumentException,它在非常类似的情况下被抛出。

所以在Java中使用断言

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

答案 8 :(得分:1)

您可以在使用时考虑这种简单的区别。异常将用于检查称为已检查和未检查错误的预期和意外错误,而断言主要用于运行时的调试目的,以查看假设是否经过验证。

答案 9 :(得分:1)

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

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

本文档提供了关于何时使用断言的最佳建议。引自文件:

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

答案 10 :(得分:0)

不幸的是,可以禁用断言。在投入生产时,您需要在追踪无法预料的事情时获得的所有帮助,因此断言会使自己失去资格。