Java 断言未充分利用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/298909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java assertions underused
提问by Dónal
I'm wondering why the assertkeyword is so underused in Java? I've almost never seen them used, but I think they're a great idea. I certainly much prefer the brevity of:
我想知道为什么assert关键字在 Java 中使用率如此低?我几乎从未见过它们被使用过,但我认为它们是个好主意。我当然更喜欢简洁的:
assert param != null : "Param cannot be null";
to the verbosity of:
详细到:
if (param == null) {
throw new IllegalArgumentException("Param cannot be null");
}
My suspicion is that they're underused because
我怀疑它们没有得到充分利用,因为
- They arrived relatively late (Java 1.4), by which time many people had already established their Java programming style/habit
- They are turned off at runtime by default
- 他们到的比较晚(Java 1.4),那时很多人已经建立了他们的 Java 编程风格/习惯
- 默认情况下它们在运行时关闭
采纳答案by Ken Gentle
assertionsare, in theory, for testing invariants, assumptions that mustbe true in order for the code to complete properly.
理论上,断言是用于测试不变量,假设必须为真才能正确完成代码。
The example shown is testing for valid input, which isn't a typical usage for an assertion because it is, generally, user supplied.
显示的示例是测试有效输入,这不是断言的典型用法,因为它通常是用户提供的。
Assertions aren't generally used in production code because there is an overhead and it is assumed that situations where the invariants fail have been caught as coding errors during development and testing.
断言通常不在生产代码中使用,因为存在开销,并且假设在开发和测试期间,不变量失败的情况已被捕获为编码错误。
Your point about them coming "late" to java is also a reason why they aren't more widely seen.
您关于它们“迟到”到 Java 的观点也是它们没有被更广泛地看到的原因。
Also, unit testing frameworks allow for some of the need for programmatic assertions to be external to the code being tested.
此外,单元测试框架允许对被测试代码外部的一些编程断言的需求。
回答by Adam Jaskiewicz
It's an abuse of assertions to use them to test user input. Throwing an IllegalArgumentExceptionon invalid input is more correct, as it allows the calling method to catch the exception, display the error, and do whatever it needs to (ask for input again, quit, whatever).
使用断言来测试用户输入是对断言的滥用。IllegalArgumentException对无效输入抛出 an更正确,因为它允许调用方法捕获异常,显示错误,并做任何它需要的事情(再次请求输入,退出等等)。
If that method is a private method inside one of your classes, the assertion is fine, because you are just trying to make sure you aren't accidentally passing it a null argument. You test with assertions on, and when you have tested all the paths through and not triggered the assertion, you can turn them off so that you aren't wasting resources on them. They are also useful just as comments. An assertat the start of a method is good documentation to maintainers that they should be following certain preconditions, and an assertat the end with a postcondition documents what the method should be doing. They can be just as useful as comments; moreso, because with assertions on, they actually TEST what they document.
如果该方法是您的某个类中的私有方法,则该断言很好,因为您只是想确保不会意外地将空参数传递给它。您使用断言进行测试,并且当您测试了所有路径并且没有触发断言时,您可以将它们关闭,这样您就不会在它们上浪费资源。它们也可用作注释。一个assert在方法的开始是很好的文档,以维护他们应该遵循一定的前提条件,并且assert在与后置的文档什么的方法应该做到底。它们和评论一样有用;此外,因为有了断言,他们实际上测试了他们记录的内容。
Assertions are for testing/debugging, not error-checking, which is why they are off by default: to discourage people from using assertions to validate user input.
断言用于测试/调试,而不是错误检查,这就是它们默认关闭的原因:阻止人们使用断言来验证用户输入。
回答by yclian
In "Effective Java", Joshua Bloch suggested (in the "Check parameters for validity" topic) that (sort of like a simple rule to adopt), for public methods, we shall validate the arguments and throw a necessary exception if found invalid, and for non-public methods (which are not exposed and you as the user of them should ensure their validity), we can use assertions instead.
在“Effective Java”中,Joshua Bloch 建议(在“检查参数的有效性”主题中)(有点像采用的简单规则),对于公共方法,我们将验证参数并在发现无效时抛出一个必要的异常,对于非公共方法(未公开,您作为它们的用户应确保其有效性),我们可以使用断言代替。
回答by Bill the Lizard
From Programming with Assertions
来自断言编程
By default, assertions are disabled at runtime. Two command-line switches allow you to selectively enable or disable assertions.
默认情况下,断言在运行时被禁用。两个命令行开关允许您有选择地启用或禁用断言。
This means that if you don't have complete control over the run-time environment, you can't guarantee that the assertion code will even be called. Assertions are meant to be used in a test-environment, not for production code. You can't replace exception handling with assertions because if the user runs your application with assertions disabled (the default), all of your error handling code disappears.
这意味着,如果您不能完全控制运行时环境,则无法保证断言代码甚至会被调用。断言旨在用于测试环境,而不是用于生产代码。您不能用断言替换异常处理,因为如果用户在禁用断言(默认)的情况下运行您的应用程序,您的所有错误处理代码都会消失。
回答by akuhn
@Don, you are frustrated that assertion are turned off by default. I was also, and thus wrote this little javac plugin that inlines them (ie emits the bytecode for if (!expr) throw Exrather than this silly assert bytecode.
@Don,您对断言默认关闭感到沮丧。我也是,因此编写了这个内联它们的小 javac 插件(即发出字节码if (!expr) throw Ex而不是这个愚蠢的断言字节码。
If you include fa.jarin your classpath while compiling Java code, it will do its magic and then tell
如果在编译 Java 代码时将fa.jar包含在类路径中,它将发挥其魔力,然后告诉
Note: %n assertions inlined.
@see http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertionsand alternatively on github https://github.com/akuhn/javac
@see http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions或者在 github https://github.com/akuhn/javac
回答by Nimbus
I'm not sure why you would bother to write asserts and then replace them with a standard if then condition statement, why not just write the conditions as ifs in the first place?
我不知道你为什么要写断言然后用标准的 if then 条件语句替换它们,为什么不首先把条件写成 ifs 呢?
Asserts are for testing only, and they have two side effects: Larger binaries and degraded performance when enabled (which is why you can turn them off!)
断言仅用于测试,它们有两个副作用:启用时更大的二进制文件和性能下降(这就是您可以关闭它们的原因!)
Asserts shouldn't be used to validate conditions because that means the behaviour of your app is different at run time when asserts are enabled/disabled - which is a nightmare!
不应该使用断言来验证条件,因为这意味着当启用/禁用断言时,您的应用程序的行为在运行时会有所不同 - 这是一场噩梦!
回答by Christophe Roussy
Assertions are useful because they:
断言很有用,因为它们:
- catch PROGRAMMING errors early
- document code using code
- 尽早发现编程错误
- 使用代码的文档代码
Think of them as code self-validation. If they fail it should mean that your program is broken and must stop. Always turn them on while unit testing !
将它们视为代码自我验证。如果它们失败,则意味着您的程序已损坏并且必须停止。在单元测试时总是打开它们!
In The Pragmatic Programmerthey even recommend to let them run in production.
在The Pragmatic Programmer 中,他们甚至建议让它们在生产中运行。
Leave Assertions Turned On
Use Assertions to Prevent the Impossible.
保持断言开启
使用断言来防止不可能的事情。
Note that assertions throw AssertionError if they fail, so not caught by catch Exception.
请注意,如果断言失败,则会抛出 AssertionError,因此不会被 catch Exception 捕获。
回答by Basil Bourque
tl;dr
tl;博士
- Yes, use assertion-testing in productionwhere it makes sense.
- Use other libraries (JUnit, AssertJ, Hamcrest, etc.) rather than the built-in
assertfacility if you wish.
Most of the other Answers on this page push the maxim "Assertions aren't generally used in production code”. While true in productivity apps such as a word-processor or spreadsheet, in custom business apps where Java is so commonly used, assertion-testing in production is extremely useful, and common.
此页面上的大多数其他答案都强调“断言通常不用于生产代码”。虽然在文字处理器或电子表格等生产力应用程序中如此,但在 Java 如此常用的自定义业务应用程序中,断言 -生产中的测试非常有用,而且很常见。
Like many maxims in the world of programming, what starts out true in one context is misconstrued and then misapplied in other contexts.
就像编程世界中的许多格言一样,在一种情况下开始时正确的东西会被误解,然后在其他情况下被误用。
Productivity Apps
生产力应用程序
This maxim of "Assertions aren't generally used in production code”, though common, is incorrect.
“断言通常不用于生产代码”的格言虽然很常见,但并不正确。
Formalized assertion-testing originated with apps such as a word-processor like Microsoft Wordor a spreadsheet like Microsoft Excel. These apps might invoke an array of assertion tests assertions on every keystrokemade by the user. Such extremerepetition impacted performance severely. So only the beta-versions of such products in limited distribution had assertions enabled. Thus the maxim.
形式化断言测试起源于诸如Microsoft Word 之类的文字处理器或Microsoft Excel 之类的电子表格之类的应用程序。这些应用程序可能会在用户每次击键时调用一系列断言测试断言。这种极端的重复严重影响了性能。因此,只有有限分发的此类产品的测试版才启用了断言。因此是格言。
Business Apps
商业应用
In contrast, in business-oriented apps for data-entry, database, or other data-processing, the use of assertion-testing in production is enormously useful. The insignificant hit on performance makes it quite practical – and common.
相比之下,在用于数据输入、数据库或其他数据处理的面向业务的应用程序中,在生产中使用断言测试非常有用。对性能的微不足道的影响使它非常实用 - 并且很常见。
Test business rules
测试业务规则
Verifying your business rules at runtime in production is entirely reasonable, and should be encouraged. For example:
在生产中的运行时验证您的业务规则是完全合理的,应该鼓励。例如:
- If an invoice must have one or more line items at all times, then write an assertion testing than the count of invoice line items is greater than zero.
- If a product name must be at least 3 characters or more, write an assertion testing the length of the string.
- When calculating the balance for a cash ledger, you know the result can never be negative, so run a check for a negative number signaling a flaw in the data or code.
- 如果发票必须始终具有一个或多个行项目,则编写断言测试比发票行项目的计数大于零。
- 如果产品名称必须至少为 3 个字符或更多,请编写一个断言测试字符串的长度。
- 在计算现金分类帐的余额时,您知道结果永远不会为负,因此请检查是否存在表示数据或代码中存在缺陷的负数。
Such tests have no significant impact on performance in production.
此类测试对生产中的性能没有显着影响。
Runtime conditions
运行时条件
If your app expects certain conditions to always be true when your app runs in production, write those expectations into your code as assertion tests.
如果您的应用程序希望在您的应用程序在生产环境中运行时某些条件始终为真,请将这些期望值作为断言测试写入您的代码中。
If you expect those conditions may reasonably on occasion fail, then do notwrite assertion tests. Perhaps throw certain exceptions. Then try to recover where possible.
如果你希望这些条件可以合理偶尔失败,然后做不写断言测试。也许抛出某些异常。然后在可能的情况下尝试恢复。
Sanity-checks
健全性检查
Sanity checksat runtime in production is also entirely reasonable, and should be encouraged. Testing a few arbitrary conditions that one could not imagine being untrue has saved my bacon in countless situations when some bizarre happening occurred.
生产中运行时的健全性检查也是完全合理的,应该鼓励。当一些奇怪的事情发生时,测试一些人们无法想象的任意条件是不真实的,这在无数情况下拯救了我的培根。
For example, testing that rounding a nickel (0.05) to the penny resulted in a nickel (0.05) in a certain library helped me in being one of the first people to discover a floating-point technology flaw that Apple shipped in their Rosettalibrary during the PowerPC-to-Intel transition. Such a flaw reaching the public would have seemed impossible. But amazingly, the flaw had escaped the notice of the originating vendor, Transitive, and Apple, and the early-access developers testing on Apple's betas.
例如,在测试舍入镍(0.05)到每一分钱,导致在某个库中的镍(0.05)帮助我成为了第一人,发现一个浮点技术的缺陷,苹果出货的罗塞塔时库PowerPC 到 Intel 的过渡。这样的缺陷传播到公众看来是不可能的。但令人惊讶的是,该缺陷没有引起原始供应商 Transitive 和 Apple 以及对 Apple 测试版进行测试的早期访问开发人员的注意。
(By the way, I should mention… never use floating-point for money, use BigDecimal.)
(顺便说一句,我应该提到......永远不要使用浮点数来表示金钱,使用BigDecimal.)
Choice of frameworks
框架的选择
Rather than use the built-in assertfacility, you may want to consider using another assertion framework. You have multiple options, including:
assert您可能需要考虑使用另一个断言框架,而不是使用内置工具。您有多种选择,包括:
- JUnit
See:org.junit.jupiter.api.Assertions. - AssertJ
Known for its slick fluent interface. - Hamcrest
Used across many languages (Java, Python, Ruby, Swift, etc.).
- JUnit
见:org.junit.jupiter.api.Assertions。 - AssertJ
以其流畅流畅的界面而闻名。 - Hamcrest
用于多种语言(Java、Python、Ruby、Swift 等)。
Or roll-your-own. Make a little class to use in your project. Something like this.
或者自己动手。制作一个小类以在您的项目中使用。像这样的东西。
package work.basil.example;
public class Assertions {
static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws java.lang.AssertionError {
if ( booleanExpression ) {
// No code needed here.
} else { // If booleanExpression is false rather than expected true, throw assertion error.
// FIXME: Add logging.
throw new java.lang.AssertionError( message.toString() );
}
}
}
Example usage:
用法示例:
Assertions.assertTrue(
localTime.isBefore( LocalTime.NOON ) ,
"The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d."
) ;
Your questions
你的问题
They arrived relatively late (Java 1.4), by which time many people had already established their Java programming style/habit
他们到的比较晚(Java 1.4),那时很多人已经建立了他们的 Java 编程风格/习惯
Yes, this is quite true. Many people were disappointed by the API that Sun/JCP developed for assertion-testing. Its design was lackluster in comparison to existing libraries. So many ignored the new API, and stuck with known tools (3rd-party tools, or roll-your-own mini-library).
是的,这是事实。许多人对 Sun/JCP 为断言测试开发的 API 感到失望。与现有的图书馆相比,它的设计乏善可陈。许多人忽略了新的 API,并坚持使用已知的工具(第 3 方工具,或推出自己的迷你库)。
They are turned off at runtime by default, WHY OH WHY??
它们在运行时默认关闭,为什么 OH 为什么?
In the earliest years, Java got a bad rap for poor performance speed. Ironically, Java quickly evolvedto become one of the best platforms for performance. But the bad rap hung around like a stinky odor. So Sun was extremely wary of anything that might in any measurable way impact performance. So in this perspective, it made sense to make disabling assertion-testing the default.
在最初的几年里,Java 因性能速度差而受到批评。具有讽刺意味的是,Java 迅速发展成为性能最佳的平台之一。但糟糕的说唱就像臭味一样四处飘荡。因此,Sun 对任何可能以任何可衡量的方式影响性能的事物都极为警惕。因此,从这个角度来看,将禁用断言测试作为默认设置是有意义的。
Another reason to disable by default might have been related to the fact that, in adding the new assertion facility, Sun had hiHymaned the word assert. This was nota previously reserved keyword, and required one of the few changes ever made to the Java language. The method name asserthad been used by many libraries and by many developers in their own code. For some discussion of this historical transition, read this old documentation, Programming With Assertions.
默认情况下禁用的另一个原因可能与以下事实有关,即在添加新的断言工具时,Sun 劫持了单词assert。这不是以前保留的关键字,并且需要对 Java 语言进行的少数更改之一。assert许多库和许多开发人员在他们自己的代码中使用了该方法名称。有关这一历史转变的一些讨论,请阅读旧文档,使用断言编程。
回答by Aaron Digulla
Assertions are very limited: You can only test boolean conditions and you need to write the code for a useful error message every time. Compare this to JUnit's assertEquals() which allows to generate a useful error message from the inputs and even show the two inputs side by side in the IDE in a JUnit runner.
断言非常有限:您只能测试布尔条件,并且每次都需要为有用的错误消息编写代码。将此与 JUnit 的 assertEquals() 进行比较,后者允许从输入生成有用的错误消息,甚至在 JUnit 运行程序的 IDE 中并排显示两个输入。
Also, you can't search for assertions in any IDE I've seen so far but every IDE can search for method invocations.
此外,您目前无法在我见过的任何 IDE 中搜索断言,但每个 IDE 都可以搜索方法调用。
回答by Denis R.
In fact they arrived in Java 1.4.
事实上,它们是在 Java 1.4 中出现的。
I think the main problem is that when you code in an environment where you do not manage JVM options directly by yourself like in Eclipseor J2EE servers (in both cases it is possible to change JVM options, but you need to deeply search to find where it can be done), it is easier (I mean it requires less effort) to use ifand exceptions (or worse not to use anything).
我认为主要的问题是,当您在不自己直接管理 JVM 选项的环境中进行编码时,例如在Eclipse或 J2EE 服务器中(在这两种情况下,都可以更改 JVM 选项,但是您需要深入搜索以找到它可以完成),使用if和异常(或更糟糕的是不使用任何东西)更容易(我的意思是它需要更少的努力)。

