异常与断言
Java 异常处理和使用 assert
条件有什么区别?
众所周知,Assert 有两种类型。 但是我们什么时候应该使用 assert
关键字呢?
What is the difference between Java exception handling and using assert
conditions?
It's known that Assert is of two types. But when should we use assert
keyword?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
使用断言进行代码中的内部逻辑检查,并使用正常异常来处理直接代码控制之外的错误情况。
不要忘记断言可以打开和关闭 - 如果您关心参数验证之类的事情,那么应该使用异常来显式地进行。 (但是,您可以选择使用断言对私有方法执行参数验证,因为此时的违规是由于内部错误而不是外部错误造成的。)
或者,它是完全合理的(IMO)对所有事情都使用例外。 我个人根本不怎么使用断言,但这在某种程度上是个人喜好的问题。 (当然可以有支持和反对断言的客观论据,但还没有足够明确的证据来完全消除偏好。)
Use assertions for internal logic checks within your code, and normal exceptions for error conditions outside your immediate code's control.
Don't forget that assertions can be turned on and off - if you care about things like argument validation, that should be explicit using exceptions. (You could, however, choose to perform argument validation on private methods using assertions, on the grounds that a violation at that point is due to an internal bug rather than an external error.)
Alternatively it's entire reasonable (IMO) to use exceptions for everything. I personally don't use assertions much at all, but it's a matter of personal preference to some extent. (There can certainly be objective arguments for and against assertions, but it's not sufficiently clear cut to remove preference altogether.)
Java 断言构建在 Java 异常和异常处理之上。 事实上,当 Java 断言失败时,结果是 AssertionError 异常,可以像任何其他 Java 异常一样捕获该异常。 异常和断言之间的主要区别是:
断言旨在仅用作检测编程错误(也称为错误)的手段。 相比之下,异常可以指示其他类型的错误或“异常”情况; 例如无效的用户输入、丢失文件、堆已满等等。
Java 语言以
assert
语句的形式提供对断言的语法支持。 比较以下内容:最重要的是,Java 允许您在启动 JVM 时全局或在单个类上启用或禁用断言检查。
注意:有些人说您应该始终在关闭断言检查的情况下运行生产代码。 我倾向于不同意将此作为笼统的声明。 如果您的生产代码已知是稳定的,并且您需要从中榨取最后一点性能,那么关闭断言是很好的选择。 但是,如果(比如说)10% 的性能下降不是真正的问题,那么我宁愿让应用程序因断言错误而终止,如果替代方案是让它继续运行并损坏重要的数据库。
@Mario Ortegón 评论道:
无论您是否认为在生产中关闭断言是好的做法,编写启用后会对性能产生重大影响的断言绝对是坏的做法。 为什么? 因为这意味着您不再可以选择在生产中(以跟踪问题)或压力/容量测试中启用断言。 在我看来,如果您需要进行
O(N^3)
前置/后置条件测试,则应该在单元测试中进行。Java assertions are built on top of Java exceptions and exception handling. Indeed, when a Java assertion fails, the result is an AssertionError exception that can be caught like any other Java exception. The key differences between exceptions and assertions are:
Assertions are intended to be used solely as a means of detecting programming errors, aka bugs. By contrast, an exception can indicate other kinds of error or "exceptional" condition; e.g. invalid user input, missing files, heap full and so on.
The Java language provides syntactic support for assertions, in the form of the
assert
statement. Compare the following:Most importantly, Java allows you to enable or disable assertion checking globally or on individual classes when you start the JVM.
Note: some people say that you should always run production code with assertion checking turned off. I tend to disagree with this as a blanket statement. If your production code is known to be stable AND you need to squeeze that last bit of performance out of it, then turning off assertions is good. But, if a (say) 10% performance hit is not a real problem, I'd prefer to have an application die with an assertion error if the alternative is for it to continue and corrupt an important database.
@Mario Ortegón commented thus:
Whether or not you think it is good practice to turn off assertions in production, it is definitely bad practice to write assertions that have a significant impact on performance when enabled. Why? Because it means that you no longer have the option of enabling assertions in production (to trace a problem) or in your stress / capacity testing. In my opinion, if you need to do
O(N^3)
pre/post-condition testing, you should do it in your unit tests.异常是一种检查实现是否在没有任何预期或意外错误的情况下执行的机制。 因此,我们看到异常基本上用于以更好的方式处理应用程序执行过程中不可预见的情况,因此有效地使用异常会产生健壮的应用程序。
断言永远不应该成为应用程序某些功能实现的一部分。 它们应该仅用于验证假设 - 只是为了确保我们在设计解决方案时所做的任何假设在实践中也确实有效。
参考:http://geekexplains.blogspot.com/2008 /06/asserions-in-java-assertions-vs.html
Exception is a mechanism of checking if the implementation is executing without any expected or unexpected errors or not. So, we see that exceptions are basically used for handling even the unforseen conditions during the execution of an application in a better way and hence using exceptions effectively results into a robust application.
Assertions should never be a part of the implementation of some functionality of the application. They should only be used to verify the assumptions - just to be sure that whatever we assumed while desinging the solution is actually valid in practical as well.
reference: http://geekexplains.blogspot.com/2008/06/asserions-in-java-assertions-vs.html
断言与异常非常相似,事实上,就像异常一样,它们会标记问题,但与异常不同的是,它们不会建议任何替代执行路径,而只会失败。
如果您可以做同样的事情,并且可以做更多的事情(但有例外),为什么还要使用断言呢?
当问题不应该被解决并且实际上从一开始就不应该发生时,请使用它们。 乍一看这听起来很奇怪:难道我们不想保护我们的代码免受所有潜在问题的影响吗? 通常是的。 但有一种情况我们不这样做。 这个案例被称为:“合同设计”。
假设您正在为一家银行撰写申请。 作为开发商,您不可能支持所有可能的财务状况。 因此,在开始编码之前,您会从银行获得一份规范,其中给出了该应用程序应支持的有效范围。 因此,您的应用程序是根据合同设计的(根据银行的规范)。 该合同将定义基本原则,这些原则应始终正确,以便您的应用程序正常运行。 这些基本原则被称为“不变量”(因为它们不能改变)。 按合同设计简化了您作为开发人员的生活 - 您只需负责支持合同中定义的工作范围。
在代码中检查这些不变量的值很重要,但您不应该像检查异常一样检查它们并尝试解决它们。 如果他们错了——你一定会失败,因为投入没有履行合同义务。
有趣的是:如果你没有在关键位置放置断言并且不变量变得无效 - 你的代码无论如何都会失败。 你只是不知道为什么。 总结一下 - 断言用于验证不变量。 它们与“合同设计”原则齐头并进。 使用它们来调试问题,这就是它们在生产中被关闭的原因。
另一个用例:如果您依赖于您不完全信任的外部库 - 您可能希望在调用它时使用断言语句。
有些人还使用断言作为异常的快速而肮脏的替代品(因为它很容易做到),但从概念上讲,这不是正确的做法。
Assertions are very similar to exceptions, in fact just like exceptions they will flag a problem, but unlike exceptions - they won’t suggest any alternative execution path, but will simply fail.
Why use assertions, if you can do the same thing, plus more with exceptions ?
Use them when the problems should not be fixed, and actually SHOULD NEVER HAPPEN IN THE FIRST PLACE. This sounds weird at first: don’t we want to safeguard our code from ALL potential problems ? Usually yes. But there is a case where we don’t. This case is called: “Design by contract”.
Let say you are writing an application for a bank. As a developer you can not possibly support all possible financial conditions. So before starting to code, you get a spec from the bank which gives you the valid ranges that this application should support. So your application is designed by a contract (by the spec from the bank). This contract will define the fundamental principles that should always be true in order for your application to work. These fundamental principles are called “invariants” (because they can’t change). Design by contract simplifies your life as a developer - you are only responsible to support the scope of work defined in the contract.
Its important to check the values of these invariants in your code, but you shouldn’t check them as if they are exceptions and try to work around them. If they are wrong - you must fail because the inputs have not fulfilled their contractual obligations.
The interesting thing is: if you don’t put an assertion into the critical place and invariants become invalid - your code will fail anyway. You just won’t know why. So to summarize - assertions are used for verifying the invariants. They go hand-in-hand with the “design by contract” principle. Use them to debug a problem, thats why they are turned off in production.
Another use case: if you are relying on an external library that you don’t completely trust - you may want to use assert statements when calling it.
Some also use assertions as a quick and dirty substitute for an exception (since its so easy to do), but conceptually that is not the proper thing to do.
虽然我已经在 se.stackexchange 站点中发布了答案,但在此处发布可能仍然有帮助。
可以使用断言。
当第一个意外情况存在一定的级联故障可能性时(即在微服务中),可能导致应用程序进入严重不一致或不可恢复的状态。
当您想在调试期间专门检测系统中的错误时。 如果语言支持,您可能希望在生产中禁用它们。
当您已经知道意外情况是由于内部错误实现而引起的,并且外部系统(即调用者)无法控制不需要的状态时。
使用异常,
当您知道由于外部系统故障(即错误的参数、缺乏资源等)而出现意外情况时。
当您知道可以使用替代路径来备份条件时,保持应用程序功能质量仍然完好无损(即,对于具有来自调用者或外部系统的正确参数的另一个调用来说,可能会很好地工作)。
当您想要记录并让开发人员了解一些不需要的状态但没什么大不了的时候。
注意:“使用断言越多,系统就越健壮”。 相比之下,“你使用异常并处理它们的次数越多,你获得的系统就越有弹性”。
[ 1 ] 快速失败 - 在系统设计中,快速失败系统是一种立即在其接口上报告任何可能指示失败的情况的系统。 快速失败系统通常设计为停止正常操作,而不是尝试继续可能有缺陷的过程。 此类设计通常会在操作中的多个点检查系统状态,因此可以及早检测到任何故障。 快速失败模块的职责是检测错误,然后让系统的下一个最高级别处理它们。
Although, I have posted the answer in se.stackexchange site, that might be still helpful to post here.
Assertions are used,
When you want to stop the program immediately rather to proceed with an unwanted state. This is often related to the philosophy of the Fail-fast [ 1 ] system design.
When there are certain possibilities of cascading failures (i.e. in microservices) for the first unexpected condition that might lead the application into severe inconsistent or unrecoverable states.
When you want to detect bugs in your system exclusively in the debugging period. You might want to disable them in production if language supports.
When you already know that the unexpected conditions arose due to your internal miss-implementation and external system (i.e the callers) has no control over the unwanted state.
Exceptions are used,
When you know that the unexpected conditions arose due to external systems fault (i.e. wrong parameters, lack of resources etc).
When you know that the conditions can be backed up with alternative paths keeping the application functional qualities still intact (i.e. might work well for another call with proper parameters from the caller or external system).
When you want to log and let the developers know about some unwanted state but not a big deal.
Note: “The more you use assertions, the more robust system you get”. In contrast “The more you use exceptions and handle them, the more resilient system you get“.
[ 1 ] Fail fast - In systems design, a fail-fast system is one which immediately reports at its interface any condition that is likely to indicate a failure. Fail-fast systems are usually designed to stop normal operation rather than attempt to continue a possibly flawed process. Such designs often check the system's state at several points in an operation, so any failures can be detected early. The responsibility of a fail-fast module is detecting errors, then letting the next-highest level of the system handle them.
良好使用 Assert 的示例:
我个人认为,当您知道某些内容超出了所需限制时,才应该使用 Assert,但您可以确定继续是相当安全的。 在所有其他情况下(请随意指出我没有想到的情况)使用异常来快速失败。
对我来说,关键的权衡是您是否想要通过异常来关闭实时/生产系统以避免损坏并使故障排除更容易,或者您是否遇到了一种情况,这种情况永远不应该允许在测试/调试版本中继续被忽视,但可以允许继续生产(当然会记录警告)。
参见 http://c2.com/cgi/wiki?FailFast 另请参阅我的 c# 副本答案:Debug.Assert 与特定引发的异常
Example of a good use of Assert:
I personally think that Assert should only be used when you know something is outside desirable limits, but you can be sure it's reasonably safe to continue. In all other circumstances (feel free point out circumstances I haven't thought of) use exceptions to fail hard and fast.
The key tradeoff for me is whether you want to bring down a live/production system with an Exception to avoid corruption and make troubleshooting easier, or whether you have encountered a situation that should never be allowed to continue unnoticed in test/debug versions but could be allowed to continue in production (logging a warning of course).
cf. http://c2.com/cgi/wiki?FailFast see also my c# copy of this answer: Debug.Assert vs. Specific Thrown Exceptions
断言仅用于调试目的,其触发条件不应发生(不应发生时为空指针等)。
异常适用于可能总是发生的特殊系统事件:FileNotFound、ConnectionToServerLost 等。
Assert is for debugging purpose only and its trigger condition should not happen (null pointer when there shouldn't be, etc.)
Exception is for special system events that may always happen : FileNotFound, ConnectionToServerLost, etc.
断言和异常处理都可以保证程序的正确性并避免逻辑错误,
但是断言可以根据程序员的意愿在编译器中启用和禁用,
如果您使用“java -ea JavaFileName”或“java -enableasserations JavaFileName”
你可以使用断言进行编译
如果程序员不需要的话,
,“java -da JavaFileName”或“java -disableasserations JavaFileName”它们可以禁用断言。 该设施不在异常处理中
Assertion and Exception Handling both can assure programme correctness and avoid logic error,
but assertion can enable and disable as programmer wish,
in compiler if you use "java -ea JavaFileName" or "java -enableasserations JavaFileName"
you can compile with assertion
if programmers don't need it ,"java -da JavaFileName " or "java -disableasserations JavaFileName " they can disable assertion.
this facility not in Exception handling
断言用于调试需要在运行时检查的假设,只需启用断言功能即可;而异常则用于在程序执行过程中检查要检查的特定条件,以防止程序终止。
Assertion is used for debugging of the required assumptions to be checked at runtime only by enabling the assert feature while exception is to check the specific conditions to be checked during execution of the program to prevent the program from terminating.
对于您期望发生的情况使用异常,对于不应该发生的情况使用用户断言。
通常,在现实世界的项目中,您希望异常能够涵盖不应该发生的条件并阻止断言变为真。 毕竟,您希望程序能够运行并且永远不会进入无效状态,因此您应该使用异常和其他技术来确保程序永远不会进入这种状态。 然而,有时,一个断言变为现实的方式有多种,而你当时只能预见到其中的几种。 因此,通过断言拥有这些“硬约束”可以确保,如果将来程序处于您没有预料到的无效状态并且它不应该发生,它就会停止,您将不得不调查这是如何发生的。
换句话说,异常检查无效的输入数据,而断言则充当检测代码中错误的机制。
Use exceptions for conditions you expect to occur, and user assertions for conditions that should never occur.
Usually, in a real-world project, you want exceptions to cover the conditions that should never happen and prevent the assertion from becoming true. After all, you want the program to operate and never get into that invalid state, so you should use exceptions and other techniques to ensure that the program never gets into such state. Sometimes, however, there are multiple ways that an assertion becomes true and you can anticipate at the time only few of them. So having these "hard-constraints" through assertions ensures that if in the future the program is in an invalid state that you haven't anticipated and that it shouldn't happen it will stop and you will have to investigate how this happened.
In other words, exceptions checks for invalid input data while assertions act as a mechanism for detecting bugs in your code.