何时使用断言以及何时使用异常
大多数时候我会使用异常来检查代码中的条件,我想知道什么时候是使用断言的合适时机?
例如,
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
}
您能否指出断言如何适合这里?我应该使用断言吗?
看来我从来没有在生产代码中使用断言,只在单元测试中看到断言。我确实知道在大多数情况下,我可以像上面那样使用异常来进行检查,但我想知道“专业”地进行检查的适当方法。
Most of the time I will use an exception to check for a condition in my code, I wonder when it is an appropriate time to use an assertion?
For instance,
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
}
Could you indicate how an assertion fits in here? Should I use an assertion?
It seems like I never use assertions in production code and only see assertions in unit tests. I do know that in most cases, I can just use exception to do the checking like above, but I want to know appropriate way to do it "professionally".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
在我看来(列表可能不完整,并且太长,无法容纳评论),我会说:
换句话说,异常解决应用程序的稳健性,而断言解决应用程序的正确性。
断言的设计成本很低,你几乎可以在任何地方使用它们,我使用的是这个经验法则:断言语句看起来越愚蠢,它就越有价值,并且它嵌入的信息越多。当调试一个行为不正确的程序时,您肯定会根据您的经验检查更明显的失败可能性。然后,您将检查不可能发生的问题:这正是断言有很大帮助并节省时间的时候。
Out of my mind (list may be incomplete, and is too long to fit in a comment), I would say:
In other words, exceptions address the robustness of your application while assertions address its correctness.
Assertions are designed to be cheap to write, you can use them almost everywhere and I'm using this rule of thumb: the more an assertion statement looks stupid, the more valuable it is and the more information it embeds. When debugging a program that does not behave the right way, you will surely check the more obvious failure possibilities based on your experience. Then you will check for problems that just cannot happen: this is exactly when assertions help a lot and save time.
断言应该用于检查不应该发生的事情,而异常应该用于检查可能发生的事情。
例如,函数可能除以 0,因此应使用异常,但可以使用断言来检查硬盘驱动器是否突然消失。
断言将使程序停止运行,但异常将使程序继续运行。
请注意,
if(group != null)
不是断言,而只是一个条件。Assertions should be used to check something that should never happen, while an exception should be used to check something that might happen.
For example, a function might divide by 0, so an exception should be used, but an assertion could be used to check that the harddrive suddenly disappears.
An assertion would stop the program from running, but an exception would let the program continue running.
Note that
if(group != null)
is not an assertion, that is just a conditional.请记住,可以使用参数在运行时禁用断言,并且 被禁用默认情况下,所以除了调试目的之外不要依赖它们。
另外,您还应该阅读有关断言的 Oracle 文章查看更多使用或不使用断言的情况。
Remember assertions can be disabled at runtime using parameters, and are disabled by default, so don't count on them except for debugging purposes.
Also you should read the Oracle article about assert to see more cases where to use - or not to use - assert.
作为一般规则:
java
命令默认关闭所有断言。)您的问题中的以下代码风格不好,并且可能存在错误。
问题是您不知道异常意味着未找到该组。
service()
调用也可能引发异常,或者返回null
,然后导致NullPointerException
。当您捕获“预期”异常时,您应该仅捕获您预期的异常。通过捕获 java.lang.Exception(尤其是不记录它),您会加大诊断/调试问题的难度,并可能导致应用造成更多损害。
As a general rule:
java
command turns off all assertions by default.)The following code from your question is bad style and potentially buggy
The problem is that you DON'T know that an exception means that the group was not found. It is also possible that the
service()
call threw an exception, or that it returnednull
which then caused aNullPointerException
.When you catch an "expected" exception, you should catch only the exception that you are expecting. By catching
java.lang.Exception
(and especially by not logging it), you are making it harder to diagnose / debug the problem, and potentially allowing the app to do more damage.好吧,回到 Microsoft,建议是在您公开提供的所有 API 中抛出异常,并在您对内部代码做出的各种假设中使用断言。这是一个有点宽松的定义,但我想这取决于每个开发人员来划定界限。
关于异常的使用,正如其名称所示,它们的使用应该是异常的,因此对于上面提供的代码,如果不存在服务,
getGroup
调用应返回null
。仅当网络链接中断或类似情况时才会发生异常。我想结论是,每个应用程序的开发团队都需要定义断言与异常的边界。
Well, back at Microsoft, the recommendation was to throw Exceptions in all APIs you make available publicly and use Asserts in all sorts of assumptions you make about code that's internal. It's a bit of a loose definition but I guess it's up to each developer to draw the line.
Regarding the use of Exceptions, as the name says, their usage should be exceptional so for the code you present above, the
getGroup
call should returnnull
if no service exists. Exception should only occur if a network link goes down or something like that.I guess the conclusion is that it's a bit left down to the development team for each application to define the boundaries of assert vs exceptions.
根据此文档 http:// /docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general, "assert 语句适用于非公共前置条件、后置条件和类不变性检查。公共前置条件检查仍应通过方法内部的检查来执行,这些检查会导致特定的记录异常,例如 IllegalArgumentException 和 IllegalStateException。”
如果您想了解有关前置条件、后置条件和类不变式的更多信息,请查看此文档:http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions。它还包含断言用法的示例。
According to this doc http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general, "The assert statement is appropriate for nonpublic precondition, postcondition and class invariant checking. Public precondition checking should still be performed by checks inside methods that result in particular, documented exceptions, such as IllegalArgumentException and IllegalStateException."
If you want to know more about precondition, postcondition and class invariant, check this doc: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions. It also contains with examples of assertions usage.
测试 null 只会捕获导致问题的 null,而 try/catch 会捕获任何错误。
一般来说,try/catch 更安全,但速度稍慢,并且您必须小心捕获可能发生的所有类型的错误。所以我想说使用 try/catch - 有一天 getGroup 代码可能会改变,你可能需要更大的网络。
Testing for null will only catch nulls causing problems, whereas a try/catch as you have it will catch any error.
Broadly, try/catch is safer, but slightly slower, and you have to be careful that you catch all the kinds of error that may occur. So I would say use try/catch - one day the getGroup code may change, and you just might need that bigger net.
您可以在使用它们时记住这个简单的区别。异常将用于检查预期和意外的错误,称为检查和未检查错误,而断言主要用于运行时的调试目的,以查看假设是否有效。
You can use this simple difference in mind while their usage. Exceptions will be used for checking expected and unexpected errors called checked and unchecked error while assertion is used mainly for debugging purposes at the run time to see whether the assumptions are validated or not.
不幸的是断言可以被禁用。在生产中,您需要在追踪不可预见的情况时获得所有帮助,因此断言会取消自己的资格。
Unfortunately asserts can be disabled. When in production you need all the help you can get when tracking down something unforeseen, so asserts disqualify themselves.
我承认我对你的问题有点困惑。当不满足断言条件时,将引发异常。令人困惑的是,这被称为 AssertionError。请注意,它是未经检查的,例如(例如) IllegalArgumentException< /a> 在非常相似的情况下抛出。
因此,在 Java 中使用断言
I confess I'm a little confused by your question. When an assertion condition is not met, an exception is thrown. Confusingly this is called AssertionError. Note that it's unchecked, like (for example) IllegalArgumentException which is thrown in very similar circumstances.
So using assertions in Java
请参阅以下链接中 Sun 文档的第 6.1.2 节(断言与其他错误代码)。
http://www.oracle.com/technetwork/articles/javase/javapch06.pdf
本文档提供了我所见过的有关何时使用断言的最佳建议。引用该文档:
“一个好的经验法则是,您应该对您想要忘记的特殊情况使用断言。断言是处理和忘记您不想忘记的条件或状态的最快方法”不要指望必须要处理。”
See section 6.1.2 (Assertions vs. other error code) of Sun's documentation at the following link.
http://www.oracle.com/technetwork/articles/javase/javapch06.pdf
This document gives the best advice I've seen on when to use assertions. Quoting from the document:
"A good rule of thumb is that you should use an assertion for exceptional cases that you would like to forget about. An assertion is the quickest way to deal with, and forget, a condition or state that you don’t expect to have to deal with."
我对 Java 断言没有经验,但我认为这里的答案很自然地遵循 Java 断言的内容:
因此我们可以推测断言永远不应该用于实现应用程序逻辑:它只能用作可选(由于开/关功能)健全性检查/显式假设。您的应用程序的正确性(模错误!)不能依赖于默认情况下关闭的运行时标志。
因此,仅使用断言来检查内部假设(仅您自己的代码,而不是像用户输入这样无法控制的事情)。但另一方面,您有时可能想使用异常来检查您的假设;如果您想始终检查某个假设,那么您不需要断言提供的开/关功能。
对于检查假设的任务,断言似乎在以下情况下表现出色:
检查可能成本高昂,因此您需要禁用它的选项
使用 if-or- throw 会产生太多“噪音”,但您可以承担一点
assert
的成本您想留下一点评论,其中仅说明以下内容:
然后Java 人员 表示您应该始终将该行替换为:
或者(在我看来)如果你愿意的话:
遵循这些原则的事情
我认为我们可以立即扩展 相关原则(兄弟答案) 通过使用这个“可选”原则(我的草书注释):
注释
我认为这是一个普遍的观点。另请参阅(我的粗体):
<块引用>
为什么 AssertionError 是 Error 的子类而不是 RuntimeException?
这个问题曾引起争议。专家组对此进行了详细讨论,并得出结论,Error 更适合阻止程序员尝试从断言失败中恢复。
I’m not experienced with Java asserts but I think the answer here naturally follows from what Java asserts are:
Thus we can surmise that assertions should never be used to implement application logic: it should only be used as optional (because of the on/off feature) sanity checks/explicit assumptions. The correctness of your app (modulo bugs!) cannot depend on a runtime flag which is turned off by default.
So only use assertions to check internal assumptions (your own code only, not things that are out of your control like user input). But on the other hand you might sometimes want to use exceptions to check your assumptions; if you want to always check a certain assumption then you don’t need the on/off feature that assertions provide.
For the task of checking assumptions, it seems that assertions excel when:
The check might be costly so you want the option of disabling it
Using if-or-throw would be too much “noise” but you can bear the cost of one little
assert <expr>
You want to leave a little comment which merely states something like:
Then the Java folks say that you should always replace that line with:
Or (in my opinion) if you prefer:
Things that follow from these principles
I think we can immediately expand on related principles (sibling answer) by using this “optional” principle (my gloss in cursive):
Notes
I think this is a general opinion. See also (my bold):