What are some real life examples to understand the key role of assertions?
有哪些现实生活中的例子可以理解断言的关键作用?
17 个解决方案
#1
363
Assertions (by way of the assert keyword) were added in Java 1.4. They are used to verify the correctness of an invariant in the code. They should never be triggered in production code, and are indicative of a bug or misuse of a code path. They can be activated at run-time by way of the -ea
option on the java
command, but are not turned on by default.
断言(通过assert关键字)在Java 1.4中添加。它们用于验证代码中不变量的正确性。它们不应该在生产代码中被触发,并且指示了错误或代码路径的误用。它们可以通过java命令上的-ea选项在运行时被激活,但默认情况下不会被打开。
An example:
一个例子:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
#2
279
Let's assume that you are supposed to write a program to control a nuclear power-plant. It is pretty obvious that even the most minor mistake could have catastrophic results, therefore your code has to be bug-free (assuming that the JVM is bug-free for the sake of the argument).
让我们假设您应该编写一个控制核电站的程序。很明显,即使是最微小的错误也可能产生灾难性的结果,因此您的代码必须是无bug的(假设JVM是无bug的,为了这个参数)。
Java is not a verifiable language, which means: you cannot calculate that the result of your operation will be perfect. The main reason for this are pointers: they can point anywhere or nowhere, therefore they cannot be calculated to be of this exact value, at least not within a reasonable span of code. Given this problem, there is no way to prove that your code is correct at a whole. But what you can do is to prove that you at least find every bug when it happens.
Java不是一种可验证的语言,这意味着:您不能计算操作的结果将是完美的。这样做的主要原因是指针:它们可以指向任何地方,也可以指向任何地方,因此它们不能被计算为这个确切的值,至少不能在合理的代码范围内。考虑到这个问题,没有办法证明您的代码在整体上是正确的。但是你能做的是证明你至少找到了每一个bug。
This idea is based on the Design-by-Contract (DbC) paradigm: you first define (with mathematical precision) what your method is supposed to do, and then verify this by testing it during actual execution. Example:
这个想法基于契约式设计(DbC)范式:您首先(以数学精度)定义您的方法应该做什么,然后在实际执行过程中通过测试来验证它。例子:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
While this is pretty obvious to work fine, most programmers will not see the hidden bug inside this one (hint: the Ariane V crashed because of a similar bug). Now DbC defines that you must always check the input and output of a function to verify that it worked correctly. Java can do this through assertions:
虽然这很明显可以很好地工作,但是大多数程序员都不会看到这个内部隐藏的bug(提示:Ariane V由于类似的bug而崩溃)。现在DbC定义,您必须始终检查函数的输入和输出,以验证它是否正确工作。Java可以通过断言来实现这一点:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Should this function now ever fail, you will notice it. You will know that there is a problem in your code, you know where it is and you know what caused it (similar to Exceptions). And what is even more important: you stop executing right when it happens to prevent any further code to work with wrong values and potentially cause damage to whatever it controls.
如果这个函数现在失败了,您将会注意到它。您将知道在您的代码中存在一个问题,您知道它在哪里,您知道它是什么引起的(类似于异常)。更重要的是:当它发生时,您停止执行正确的操作,以防止任何其他代码错误地工作,并可能对它所控制的任何代码造成损害。
Java Exceptions are a similar concept, but they fail to verify everything. If you want even more checks (at the cost of execution speed) you need to use assertions. Doing so will bloat your code, but you can in the end deliver a product at a surprisingly short development time (the earlier you fix a bug, the lower the cost). And in addition: if there is any bug inside your code, you will detect it. There is no way of a bug slipping-through and cause issues later.
Java异常是一个类似的概念,但是它们不能验证所有的东西。如果您想要更多的检查(以执行速度为代价),您需要使用断言。这样做会增加代码的负担,但最终您可以在非常短的开发时间内交付产品(修复bug越早,成本越低)。此外:如果您的代码中有任何错误,您将检测到它。没有任何一种错误的方法会在以后导致问题。
This still is not a guarantee for bug-free code, but it is much closer to that, than usual programs.
这仍然不能保证没有bug的代码,但是它比通常的程序更接近于这一点。
#3
48
Assertions are a development-phase tool to catch bugs in your code. They're designed to be easily removed, so they won't exist in production code. So assertions are not part of the "solution" that you deliver to the customer. They're internal checks to make sure that the assumptions you're making are correct. The most common example is to test for null. Many methods are written like this:
断言是一种开发阶段的工具,用于捕获代码中的错误。它们被设计成易于删除,因此它们不会存在于产品代码中。因此断言不是您交付给客户的“解决方案”的一部分。它们是内部检查,以确保你所做的假设是正确的。最常见的示例是测试null。许多方法是这样写的:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Very often in a method like this, the widget should simply never be null. So if it's null, there's a bug in your code somewhere that you need to track down. But the code above will never tell you this. So in a well-intentioned effort to write "safe" code, you're also hiding a bug. It's much better to write code like this:
在类似这样的方法中,小部件通常不应该是空的。如果它是空的,你的代码中有一个错误需要你去追踪。但是上面的代码永远不会告诉你这些。因此,在编写“安全”代码时,出于善意,您还隐藏了一个bug。最好这样写代码:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
This way, you will be sure to catch this bug early. (It's also useful to specify in the contract that this parameter should never be null.) Be sure to turn assertions on when you test your code during development. (And persuading your colleagues to do this, too is often difficult, which I find very annoying.)
通过这种方式,您将确保尽早捕获这个bug。(在合同中指定这个参数不应该为null也是很有用的。)在开发期间测试代码时,一定要打开断言。(说服你的同事也这么做也很困难,我觉得这很烦人。)
Now, some of your colleagues will object to this code, arguing that you should still put in the null check to prevent an exception in production. In that case, the assertion is still useful. You can write it like this:
现在,您的一些同事将会反对这段代码,争论说您应该仍然输入null检查以防止在生产中出现异常。在这种情况下,断言仍然有用。你可以这样写:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
This way, your colleagues will be happy that the null check is there for production code, but during development, you're no longer hiding the bug when widget is null.
这样,您的同事会很高兴地看到产品代码有null检查,但是在开发过程中,当小部件为null时,您不再隐藏错误。
Here's a real-world example: I once wrote a method that compared two arbitrary values for equality, where either value could be null:
这里有一个真实的例子:我曾经写过一个方法,比较两个任意值的相等性,其中任何一个值都可以为null:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
This code delegates the work of the equals()
method in the case where thisValue is not null. But it assumes the equals()
method correctly fulfills the contract of equals()
by properly handling a null parameter.
该代码将equals()方法的工作委托给不为null的情况。但是它假设equals()方法通过正确地处理一个空参数来正确地履行equals()的约定。
A colleague objected to my code, telling me that many of our classes have buggy equals()
methods that don't test for null, so I should put that check into this method. It's debatable if this is wise, or if we should force the error, so we can spot it and fix it, but I deferred to my colleague and put in a null check, which I've marked with a comment:
一位同事反对我的代码,他告诉我,我们的许多类都有不测试null的错误的equals()方法,所以我应该把这个检查放到这个方法中。这是有争议的,如果这是明智的,或者我们是否应该强制这个错误,这样我们就可以发现并修复它,但是我把它推迟到我的同事那里,并进行了一个null校验,我用注释标记了一下:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
The additional check here, other != null
, is only necessary if the equals()
method fails to check for null as required by its contract.
这里的附加检查other != null仅在equals()方法不能按照其约定检查null时才需要。
Rather than engage in a fruitless debate with my colleague about the wisdom of letting the buggy code stay in our code base, I simply put two assertions in the code. These assertions will let me know, during the development phase, if one of our classes fails to implement equals()
properly, so I can fix it:
与其与我的同事进行徒劳无益的讨论,讨论让错误代码保留在我们的代码库中是否明智,不如在代码中加入两个断言。在开发阶段,如果我们的某个类不能正确地实现equals(),那么我就可以修复它:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
The important points to keep in mind are these:
要记住的要点是:
-
Assertions are development-phase tools only.
断言只是开发阶段的工具。
-
The point of an assertion is to let you know if there's a bug, not just in your code, but in your code base. (The assertions here will actually flag bugs in other classes.)
断言的要点是让您知道是否存在bug,不仅在您的代码中,而且在您的代码库中。(这里的断言实际上会标记其他类中的bug。)
-
Even if my colleague was confident that our classes were properly written, the assertions here would still be useful. New classes will be added that might fail to test for null, and this method can flag those bugs for us.
即使我的同事确信我们的类是正确编写的,这里的断言仍然是有用的。将添加可能无法测试null的新类,该方法可以为我们标记这些错误。
-
In development, you should always turn assertions on, even if the code you've written doesn't use assertions. My IDE is set to always do this by default for any new executable.
在开发中,应该始终打开断言,即使您编写的代码不使用断言。我的IDE设置为对任何新的可执行文件总是默认这样做。
-
The assertions don't change the behavior of the code in production, so my colleague is happy that the null check is there, and that this method will execute properly even if the
equals()
method is buggy. I'm happy because I will catch any buggyequals()
method in development.断言不会改变代码在生产环境中的行为,因此我的同事很高兴有null检查,而且即使equals()方法存在错误,该方法也会正确执行。我很高兴,因为在开发过程中我将捕获任何bug equals()方法。
Also, you should test your assertion policy by putting in a temporary assertion that will fail, so you can be certain that you are notified, either through the log file or a stack trace in the output stream.
此外,您应该通过放入一个将失败的临时断言来测试断言策略,这样您就可以确定您是通过日志文件或输出流中的堆栈跟踪被通知的。
#4
15
A lot of good answers explaining what the assert
keyword does, but few answering the real question, "when should the assert
keyword be used in real life?"
很多很好的答案解释了assert关键字的作用,但是很少有人回答真正的问题:“断言关键字在现实生活中什么时候应该使用?”
The answer: almost never.
答案是:几乎没有。
Assertions, as a concept, are wonderful. Good code has lots of if (...) throw ...
statements (and their relatives like Objects.requireNonNull
and Math.addExact
). However, certain design decisions have greatly limited the utility of the assert
keyword itself.
断言,作为一个概念,是美妙的。好的代码有很多if(…)抛出…语句(以及它们的亲戚喜欢对象。requireNonNull和Math.addExact)。然而,某些设计决策极大地限制了assert关键字本身的用途。
The driving idea behind the assert
keyword is premature optimization, and the main feature is being able to easily turn off all checks. In fact, the assert
checks are turned off by default.
assert关键字背后的驱动思想是不成熟的优化,主要特性是能够轻松关闭所有检查。事实上,断言检查在默认情况下是关闭的。
However, it is critically important that invariant checks continue to be done in production. This is because perfect test coverage is impossible, and all production code will have bugs which assertions should help to diagnose and mitigate.
然而,在生产中继续进行不变量检查是至关重要的。这是因为完美的测试覆盖是不可能的,并且所有的产品代码都会有错误,断言应该有助于诊断和减轻错误。
Therefore, the use of if (...) throw ...
should be preferred, just as it is required for checking parameter values of public methods and for throwing IllegalArgumentException
.
因此,使用if(…)抛出…应该优先,就像检查公共方法的参数值和抛出IllegalArgumentException所需要的那样。
Occasionally, one might be tempted to write an invariant check that does take an undesirably long time to process (and is called often enough for it to matter). However, such checks will slow down testing which is also undesirable. Such time-consuming checks are usually written as unit tests. Nevertheless, it may sometimes make sense to use assert
for this reason.
偶尔,您可能会想要编写一个不变量检查,它确实需要很长时间来处理(并且经常被调用,这足以让它起作用)。然而,这样的检查将减慢测试,这也是不可取的。这种耗时的检查通常被写成单元测试。然而,出于这个原因,有时使用assert可能是有意义的。
Do not use assert
simply because it is cleaner and prettier than if (...) throw ...
(and I say that with great pain, because I like clean and pretty). If you just cannot help yourself, and can control how your application is launched, then feel free to use assert
but always enable assertions in production. Admittedly, this is what I tend to do. I am pushing for a lombok annotation that will cause assert
to act more like if (...) throw ...
. Vote for it here.
不要仅仅因为它比扔(…)更干净、更漂亮就使用assert。(我很痛苦地说,因为我喜欢干净和漂亮)。如果您不能帮助自己,并且可以控制应用程序的启动方式,那么可以随意使用断言,但在生产中始终支持断言。诚然,这是我倾向于做的。我推动lombok注释,将导致维护像如果(…)....为在这里投票。
(Rant: the JVM devs were a bunch of awful, prematurely optimizing coders. That is why you hear about so many security issues in the Java plugin and JVM. They refused to include basic checks and assertions in production code, and we are continuing to pay the price.)
(Rant: JVM devs是一堆糟糕的、过早优化的程序员。这就是为什么您会在Java插件和JVM中听到这么多安全问题。他们拒绝在生产代码中包含基本的检查和断言,我们将继续为此付出代价。
#5
11
Here's the most common use case. Suppose you're switching on an enum value:
这是最常见的用例。假设您正在打开enum值:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
As long as you handle every case, you're fine. But someday, somebody will add fig to your enum and forget to add it to your switch statement. This produces a bug that may get tricky to catch, because the effects won't be felt until after you've left the switch statement. But if you write your switch like this, you can catch it immediately:
只要你处理好每一个案子,你就没事了。但是总有一天,有人会在你的enum中添加一个图,忘记把它添加到你的switch语句中。这会产生一个可能难以捕获的bug,因为直到您离开switch语句之后才会感觉到影响。但是如果你像这样写你的开关,你可以立刻抓住它:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
#6
9
Assertions are used to check post-conditions and "should never fail" pre-conditions. Correct code should never fail an assertion; when they trigger, they should indicate a bug (hopefully at a place that is close to where the actual locus of the problem is).
断言用于检查后置条件和“不应该失败”前置条件。正确的代码永远不会出错;当它们触发时,它们应该指出一个错误(希望在一个接近问题所在位置的地方)。
An example of an assertion might be to check that a particular group of methods is called in the right order (e.g., that hasNext()
is called before next()
in an Iterator
).
断言的一个示例可能是检查以正确的顺序调用特定的一组方法(例如,在迭代器中的next()之前调用hasNext()))。
#7
6
What does the assert keyword in Java do?
Java中的assert关键字做什么?
Let's look at the compiled bytecode.
让我们看一下编译后的字节码。
We will conclude that:
我们会得出这样的结论::
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
generates almost the exact same bytecode as:
生成几乎完全相同的字节码:
public class Assert {
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
where Assert.class.desiredAssertionStatus()
is true
when -ea
is passed on the command line, and false otherwise.
在命令行上传递-ea时,Assert.class.desiredAssertionStatus()为true,否则为false。
We use System.currentTimeMillis()
to ensure that it won't get optimized away (assert true;
did).
我们使用System.currentTimeMillis()确保它不会被优化(assert true;所做的那样)。
The synthetic field is generated so that Java only needs to call Assert.class.desiredAssertionStatus()
once at load time, and it then caches the result there. See also: What is the meaning of "static synthetic"?
生成合成字段,以便Java只需要在加载时调用一次Assert.class.desiredAssertionStatus(),然后在那里缓存结果。参见:“静态合成”的含义是什么?
We can verify that with:
我们可以用:
javac Assert.java
javap -c -constants -private -verbose Assert.class
With Oracle JDK 1.8.0_45, a synthetic static field was generated (see also: What is the meaning of "static synthetic"?):
在Oracle JDK 1.8.0_45中,生成了一个合成的静态字段(参见:“静态合成”的含义是什么?):
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
together with a static initializer:
与静态初始化器一起:
0: ldc #6 // class Assert
2: invokevirtual #7 // Method java/lang Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #2 // Field $assertionsDisabled:Z
16: return
and the main method is:
主要方法是:
0: getstatic #2 // Field $assertionsDisabled:Z
3: ifne 22
6: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
9: lconst_0
10: lcmp
11: ifeq 22
14: new #4 // class java/lang/AssertionError
17: dup
18: invokespecial #5 // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
We conclude that:
我们得出结论:
- there is no bytecode level support for
assert
: it is a Java language concept - 对于assert没有字节码级支持:它是一个Java语言概念
-
assert
could be emulated pretty well with system properties-Pcom.me.assert=true
to replace-ea
on the command line, and athrow new AssertionError()
. - 断言可以很好地模拟系统属性-Pcom.me。assert=true用于替换命令行上的-ea,以及抛出新的AssertionError()。
#8
6
A real world example, from a Stack-class (from Assertion in Java Articles)
来自堆栈类的真实世界示例(来自Java文章中的断言)
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
#9
4
In addition to all the great answers provided here, the official Java SE 7 programming guide has a pretty concise manual on using assert
; with several spot-on examples of when it's a good (and, importantly, bad) idea to use assertions, and how it's different from throwing exceptions.
除了这里提供的所有优秀答案之外,官方Java SE 7编程指南还提供了使用assert的简明手册;有几个恰当的例子说明什么时候使用断言是一个好(重要的是,坏)的主意,以及它与抛出异常的区别。
链接
#10
3
An assertion allows for detecting defects in the code. You can turn on assertions for testing and debugging while leaving them off when your program is in production.
断言允许检测代码中的缺陷。您可以打开用于测试和调试的断言,而在程序在生产时关闭它们。
Why assert something when you know it is true? It is only true when everything is working properly. If the program has a defect, it might not actually be true. Detecting this earlier in the process lets you know something is wrong.
当你知道这是真的时,为什么要断言某事?只有当一切都正常运转时,它才成立。如果程序有缺陷,它实际上可能不是真的。在这个过程的早期发现这一点让您知道有些事情是错误的。
An assert
statement contains this statement along with an optional String
message.
assert语句和一个可选的字符串消息一起包含该语句。
The syntax for an assert statement has two forms:
assert语句的语法有两种形式:
assert boolean_expression;
assert boolean_expression: error_message;
Here are some basic rules which govern where assertions should be used and where they should not be used. Assertions should be used for:
下面是一些基本规则,它们控制应该在哪里使用断言,在哪里不应该使用断言。断言应用于:
-
Validating input parameters of a private method. NOT for public methods.
public
methods should throw regular exceptions when passed bad parameters.验证私有方法的输入参数。不是公共方法。当传递坏参数时,公共方法应该抛出常规异常。
-
Anywhere in the program to ensure the validity of a fact which is almost certainly true.
在程序的任何地方,确保一个事实的正确性,这几乎是正确的。
For example, if you are sure that it will only be either 1 or 2, you can use an assertion like this:
例如,如果您确定只有1或2,您可以使用如下断言:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
- Validating post conditions at the end of any method. This means, after executing the business logic, you can use assertions to ensure that the internal state of your variables or results is consistent with what you expect. For example, a method that opens a socket or a file can use an assertion at the end to ensure that the socket or the file is indeed opened.
- 在任何方法的末尾验证post条件。这意味着,在执行业务逻辑之后,您可以使用断言来确保变量或结果的内部状态与预期一致。例如,打开套接字或文件的方法可以在末尾使用断言,以确保套接字或文件确实被打开。
Assertions should not be used for:
不应使用断言:
-
Validating input parameters of a public method. Since assertions may not always be executed, the regular exception mechanism should be used.
验证公共方法的输入参数。由于断言可能并不总是被执行,所以应该使用常规异常机制。
-
Validating constraints on something that is input by the user. Same as above.
验证用户输入的内容的约束。与上面一样。
-
Should not be used for side effects.
不应用于副作用。
For example this is not a proper use because here the assertion is used for its side effect of calling of the doSomething()
method.
例如,这不是一个合适的用法,因为这里使用断言的副作用是调用doSomething()方法。
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
The only case where this could be justified is when you are trying to find out whether or not assertions are enabled in your code:
唯一可以证明这一点的情况是,当您试图查明您的代码中是否启用了断言时:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Assertions are enabled")
} else {
System.out.println("Assertions are disabled")
}
#11
1
Assert is very useful when developing. You use it when something just cannot happen if your code is working correctly. It's easy to use, and can stay in the code for ever, because it will be turned off in real life.
Assert在开发时非常有用。如果代码正常工作,就不能使用它。它很容易使用,并且可以永远留在代码中,因为在现实生活中它将被关闭。
If there is any chance that the condition can occur in real life, then you must handle it.
如果在现实生活中有任何可能出现这种情况,那么你必须处理它。
I love it, but don't know how to turn it on in Eclipse/Android/ADT . It seems to be off even when debugging. (There is a thread on this, but it refers to the 'Java vm', which does not appear in the ADT Run Configuration).
我喜欢它,但不知道如何在Eclipse/Android/ADT中打开它。即使在调试的时候,它似乎也是关闭的。(上面有一个线程,但它指的是“Java vm”,它不出现在ADT Run配置中)。
#12
1
Here's an assertion I wrote in a server for a Hibernate/SQL project. An entity bean had two effectively-boolean properties, called isActive and isDefault. Each could have a value of "Y" or "N" or null, which was treated as "N". We want to make sure the browser client is limited to these three values. So, in my setters for these two properties, I added this assertion:
下面是我在服务器上为Hibernate/SQL项目编写的断言。实体bean有两个有效的布尔属性,即isActive和isDefault。每个值都可以有“Y”或“N”或null,被当作“N”。我们希望确保浏览器客户端仅限于这三个值。因此,在我的setter中,这两个属性,我添加了这个断言:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Notice the following.
请注意以下。
-
This assertion is for the development phase only. If the client sends a bad value, we will catch that early and fix it, long before we reach production. Assertions are for defects that you can catch early.
此断言仅适用于开发阶段。如果客户发送了一个错误的值,我们将尽早捕获并修复它,在我们到达生产阶段之前。断言是关于您可以及早发现的缺陷的。
-
This assertion is slow and inefficient. That's okay. Assertions are free to be slow. We don't care because they're development-only tools. This won't slow down the production code because assertions will be disabled. (There's some disagreement on this point, which I'll get to later.) This leads to my next point.
这种断言是缓慢而低效的。没关系。断言是可以慢慢来的。我们不在乎,因为它们只是开发工具。这不会减慢生产代码,因为断言将被禁用。(在这一点上有一些分歧,我稍后会讲到。)这就引出了我的下一个观点。
-
This assertion has no side effects. I could have tested my value against an unmodifiable static final Set, but that set would have stayed around in production, where it would never get used.
这个断言没有副作用。我本来可以用一个不可修改的静态最终集来测试我的值,但是这个集合将会一直存在于生产中,在那里它永远不会被使用。
-
This assertion exists to verify the proper operation of the client. So by the time we reach production, we will be sure that the client is operating properly, so we can safely turn the assertion off.
存在此断言是为了验证客户机的正确操作。因此,当我们到达生产阶段时,我们将确保客户端正在正常运行,因此我们可以安全地关闭断言。
-
Some people ask this: If the assertion isn't needed in production, why not just take them out when you're done? Because you'll still need them when you start working on the next version.
有些人会问:如果在生产过程中不需要这个断言,为什么不直接把它们去掉呢?因为当您开始开发下一个版本时仍然需要它们。
Some people have argued that you should never use assertions, because you can never be sure that all the bugs are gone, so you need to keep them around even in production. And so there's no point in using the assert statement, since the only advantage to asserts is that you can turn them off. Hence, according to this thinking, you should (almost) never use asserts. I disagree. It's certainly true that if a test belongs in production, you should not use an assert. But this test does not belong in production. This one is for catching a bug that's not likely to ever reach production, so it may safely be turned off when you're done.
有些人认为您不应该使用断言,因为您永远无法确定所有的bug都消失了,因此您需要将它们保留在产品中。因此,使用assert语句没有任何意义,因为断言的惟一好处是可以关闭它们。我不同意。当然,如果测试属于生产环境,则不应该使用assert。但是这个测试不属于生产。这个程序是用来捕获一个不太可能实现生产的bug,所以当您完成时,它可以安全地关闭。
BTW, I could have written it like this:
顺便说一句,我可以这样写:
assert value == null || value.equals("Y") || value.equals("N") : value;
This is fine for only three values, but if the number of possible values gets bigger, the HashSet version becomes more convenient. I chose the HashSet version to make my point about efficiency.
这只适用于三个值,但是如果可能值的数量变大,HashSet版本就变得更方便了。我选择HashSet版本是为了说明效率。
#13
1
Assertions are disabled by default. To enable them we must run the program with -ea
options (granularity can be varied). For example, java -ea AssertionsDemo
.
默认情况下禁用断言。要启用它们,我们必须使用-ea选项运行程序(粒度可以变化)。例如,java -ea AssertionsDemo。
There are two formats for using assertions:
使用断言有两种格式:
- Simple: eg.
assert 1==2; // This will raise an AssertionError
. - 简单:如。维护1 = = 2;//这将引发断言错误。
- Better:
assert 1==2: "no way.. 1 is not equal to 2";
This will raise an AssertionError with the message given displayed too and is thus better. Although the actual syntax isassert expr1:expr2
where expr2 can be any expression returning a value, I have used it more often just to print a message. - 更好:断言1= 2:“没门。1不等于2"这将引发一个AssertionError,并显示所显示的消息,因此更好。虽然实际的语法是assert expr1:expr2,其中expr2可以是任何返回值的表达式,但我更常用它来打印消息。
#14
0
To recap (and this is true of many languages not just Java):
总结一下(这不仅适用于Java,也适用于许多语言):
"assert" is primarily used as a debugging aid by software developers during the debugging process. Assert-messages should never appear. Many languages provide a compile-time option that will cause all "asserts" to be ignored, for use in generating "production" code.
“assert”主要用于软件开发人员在调试过程中的调试辅助。Assert-messages就不应该出现。许多语言提供了编译时选项,该选项将导致忽略所有的“断言”,以便用于生成“生产”代码。
"exceptions" are a handy way to handle all kinds of error conditions, whether or not they represent logic errors, because, if you run into an error-condition such that you cannot continue, you can simply "throw them up into the air," from wherever you are, expecting someone else out there to be ready to "catch" them. Control is transferred in one step, straight from the code that threw the exception, straight to the catcher's mitt. (And the catcher can see the complete backtrace of calls that had taken place.)
“例外”是一个方便的方式来处理各种各样的错误条件,是否代表逻辑错误,因为,如果你遇到一个错误条件,你不能继续,您可以简单地“扔到空中,“无论你在哪里,希望有人也准备“捕获”它们。控制在一步中转移,直接从抛出异常的代码,直接到捕手的手套。(捕鲸者可以看到所发生的全部通话记录。)
Furthermore, callers of that subroutine don't have to check to see if the subroutine succeeded: "if we're here now, it must have succeeded, because otherwise it would have thrown an exception and we wouldn't be here now!" This simple strategy makes code-design and debugging much, much easier.
此外,该子例程的调用者不必检查子例程是否成功:“如果我们现在在这里,它一定成功了,否则它会抛出一个异常,我们现在就不会在这里了!”这个简单的策略使代码设计和调试更加容易。
Exceptions conveniently allow fatal-error conditions to be what they are: "exceptions to the rule." And, for them to be handled by a code-path that is also "an exception to the rule ... "fly ball!"
异常可以方便地允许致命错误条件是它们本身:“规则的异常”。而且,对于它们,代码路径也是“规则的例外……”“高飞球!”
#15
0
Assertion are basically used to debug the application or it is used in replacement of exception handling for some application to check the validity of an application.
断言主要用于调试应用程序,或者用于替换某些应用程序的异常处理,以检查应用程序的有效性。
Assertion works at run time. A simple example, that can explain the whole concept very simply, is herein - What does the assert keyword do in Java? (WikiAnswers).
断言在运行时工作。一个简单的例子,可以很简单地解释整个概念——在Java中,assert关键字是干什么的?(WikiAnswers)。
#16
0
Basically, "assert true" will pass and "assert false" will fail. Let's looks at how this will work:
基本上,“assert true”将通过,“assert false”将失败。让我们看看它是如何工作的:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
#17
-8
assert
is a keyword. It was introduced in JDK 1.4. The are two types of assert
s
断言是一个关键词。它是在JDK 1.4中引入的。有两种类型的断言
- Very simple
assert
statements - 非常简单的断言语句
- Simple
assert
statements. - 简单的断言语句。
By default all assert
statements will not be executed. If an assert
statement receives false, then it will automatically raise an assertion error.
默认情况下,不会执行所有assert语句。如果断言语句接收到false,那么它将自动引发断言错误。
#1
363
Assertions (by way of the assert keyword) were added in Java 1.4. They are used to verify the correctness of an invariant in the code. They should never be triggered in production code, and are indicative of a bug or misuse of a code path. They can be activated at run-time by way of the -ea
option on the java
command, but are not turned on by default.
断言(通过assert关键字)在Java 1.4中添加。它们用于验证代码中不变量的正确性。它们不应该在生产代码中被触发,并且指示了错误或代码路径的误用。它们可以通过java命令上的-ea选项在运行时被激活,但默认情况下不会被打开。
An example:
一个例子:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
#2
279
Let's assume that you are supposed to write a program to control a nuclear power-plant. It is pretty obvious that even the most minor mistake could have catastrophic results, therefore your code has to be bug-free (assuming that the JVM is bug-free for the sake of the argument).
让我们假设您应该编写一个控制核电站的程序。很明显,即使是最微小的错误也可能产生灾难性的结果,因此您的代码必须是无bug的(假设JVM是无bug的,为了这个参数)。
Java is not a verifiable language, which means: you cannot calculate that the result of your operation will be perfect. The main reason for this are pointers: they can point anywhere or nowhere, therefore they cannot be calculated to be of this exact value, at least not within a reasonable span of code. Given this problem, there is no way to prove that your code is correct at a whole. But what you can do is to prove that you at least find every bug when it happens.
Java不是一种可验证的语言,这意味着:您不能计算操作的结果将是完美的。这样做的主要原因是指针:它们可以指向任何地方,也可以指向任何地方,因此它们不能被计算为这个确切的值,至少不能在合理的代码范围内。考虑到这个问题,没有办法证明您的代码在整体上是正确的。但是你能做的是证明你至少找到了每一个bug。
This idea is based on the Design-by-Contract (DbC) paradigm: you first define (with mathematical precision) what your method is supposed to do, and then verify this by testing it during actual execution. Example:
这个想法基于契约式设计(DbC)范式:您首先(以数学精度)定义您的方法应该做什么,然后在实际执行过程中通过测试来验证它。例子:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
While this is pretty obvious to work fine, most programmers will not see the hidden bug inside this one (hint: the Ariane V crashed because of a similar bug). Now DbC defines that you must always check the input and output of a function to verify that it worked correctly. Java can do this through assertions:
虽然这很明显可以很好地工作,但是大多数程序员都不会看到这个内部隐藏的bug(提示:Ariane V由于类似的bug而崩溃)。现在DbC定义,您必须始终检查函数的输入和输出,以验证它是否正确工作。Java可以通过断言来实现这一点:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Should this function now ever fail, you will notice it. You will know that there is a problem in your code, you know where it is and you know what caused it (similar to Exceptions). And what is even more important: you stop executing right when it happens to prevent any further code to work with wrong values and potentially cause damage to whatever it controls.
如果这个函数现在失败了,您将会注意到它。您将知道在您的代码中存在一个问题,您知道它在哪里,您知道它是什么引起的(类似于异常)。更重要的是:当它发生时,您停止执行正确的操作,以防止任何其他代码错误地工作,并可能对它所控制的任何代码造成损害。
Java Exceptions are a similar concept, but they fail to verify everything. If you want even more checks (at the cost of execution speed) you need to use assertions. Doing so will bloat your code, but you can in the end deliver a product at a surprisingly short development time (the earlier you fix a bug, the lower the cost). And in addition: if there is any bug inside your code, you will detect it. There is no way of a bug slipping-through and cause issues later.
Java异常是一个类似的概念,但是它们不能验证所有的东西。如果您想要更多的检查(以执行速度为代价),您需要使用断言。这样做会增加代码的负担,但最终您可以在非常短的开发时间内交付产品(修复bug越早,成本越低)。此外:如果您的代码中有任何错误,您将检测到它。没有任何一种错误的方法会在以后导致问题。
This still is not a guarantee for bug-free code, but it is much closer to that, than usual programs.
这仍然不能保证没有bug的代码,但是它比通常的程序更接近于这一点。
#3
48
Assertions are a development-phase tool to catch bugs in your code. They're designed to be easily removed, so they won't exist in production code. So assertions are not part of the "solution" that you deliver to the customer. They're internal checks to make sure that the assumptions you're making are correct. The most common example is to test for null. Many methods are written like this:
断言是一种开发阶段的工具,用于捕获代码中的错误。它们被设计成易于删除,因此它们不会存在于产品代码中。因此断言不是您交付给客户的“解决方案”的一部分。它们是内部检查,以确保你所做的假设是正确的。最常见的示例是测试null。许多方法是这样写的:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Very often in a method like this, the widget should simply never be null. So if it's null, there's a bug in your code somewhere that you need to track down. But the code above will never tell you this. So in a well-intentioned effort to write "safe" code, you're also hiding a bug. It's much better to write code like this:
在类似这样的方法中,小部件通常不应该是空的。如果它是空的,你的代码中有一个错误需要你去追踪。但是上面的代码永远不会告诉你这些。因此,在编写“安全”代码时,出于善意,您还隐藏了一个bug。最好这样写代码:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
This way, you will be sure to catch this bug early. (It's also useful to specify in the contract that this parameter should never be null.) Be sure to turn assertions on when you test your code during development. (And persuading your colleagues to do this, too is often difficult, which I find very annoying.)
通过这种方式,您将确保尽早捕获这个bug。(在合同中指定这个参数不应该为null也是很有用的。)在开发期间测试代码时,一定要打开断言。(说服你的同事也这么做也很困难,我觉得这很烦人。)
Now, some of your colleagues will object to this code, arguing that you should still put in the null check to prevent an exception in production. In that case, the assertion is still useful. You can write it like this:
现在,您的一些同事将会反对这段代码,争论说您应该仍然输入null检查以防止在生产中出现异常。在这种情况下,断言仍然有用。你可以这样写:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
This way, your colleagues will be happy that the null check is there for production code, but during development, you're no longer hiding the bug when widget is null.
这样,您的同事会很高兴地看到产品代码有null检查,但是在开发过程中,当小部件为null时,您不再隐藏错误。
Here's a real-world example: I once wrote a method that compared two arbitrary values for equality, where either value could be null:
这里有一个真实的例子:我曾经写过一个方法,比较两个任意值的相等性,其中任何一个值都可以为null:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
This code delegates the work of the equals()
method in the case where thisValue is not null. But it assumes the equals()
method correctly fulfills the contract of equals()
by properly handling a null parameter.
该代码将equals()方法的工作委托给不为null的情况。但是它假设equals()方法通过正确地处理一个空参数来正确地履行equals()的约定。
A colleague objected to my code, telling me that many of our classes have buggy equals()
methods that don't test for null, so I should put that check into this method. It's debatable if this is wise, or if we should force the error, so we can spot it and fix it, but I deferred to my colleague and put in a null check, which I've marked with a comment:
一位同事反对我的代码,他告诉我,我们的许多类都有不测试null的错误的equals()方法,所以我应该把这个检查放到这个方法中。这是有争议的,如果这是明智的,或者我们是否应该强制这个错误,这样我们就可以发现并修复它,但是我把它推迟到我的同事那里,并进行了一个null校验,我用注释标记了一下:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
The additional check here, other != null
, is only necessary if the equals()
method fails to check for null as required by its contract.
这里的附加检查other != null仅在equals()方法不能按照其约定检查null时才需要。
Rather than engage in a fruitless debate with my colleague about the wisdom of letting the buggy code stay in our code base, I simply put two assertions in the code. These assertions will let me know, during the development phase, if one of our classes fails to implement equals()
properly, so I can fix it:
与其与我的同事进行徒劳无益的讨论,讨论让错误代码保留在我们的代码库中是否明智,不如在代码中加入两个断言。在开发阶段,如果我们的某个类不能正确地实现equals(),那么我就可以修复它:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
The important points to keep in mind are these:
要记住的要点是:
-
Assertions are development-phase tools only.
断言只是开发阶段的工具。
-
The point of an assertion is to let you know if there's a bug, not just in your code, but in your code base. (The assertions here will actually flag bugs in other classes.)
断言的要点是让您知道是否存在bug,不仅在您的代码中,而且在您的代码库中。(这里的断言实际上会标记其他类中的bug。)
-
Even if my colleague was confident that our classes were properly written, the assertions here would still be useful. New classes will be added that might fail to test for null, and this method can flag those bugs for us.
即使我的同事确信我们的类是正确编写的,这里的断言仍然是有用的。将添加可能无法测试null的新类,该方法可以为我们标记这些错误。
-
In development, you should always turn assertions on, even if the code you've written doesn't use assertions. My IDE is set to always do this by default for any new executable.
在开发中,应该始终打开断言,即使您编写的代码不使用断言。我的IDE设置为对任何新的可执行文件总是默认这样做。
-
The assertions don't change the behavior of the code in production, so my colleague is happy that the null check is there, and that this method will execute properly even if the
equals()
method is buggy. I'm happy because I will catch any buggyequals()
method in development.断言不会改变代码在生产环境中的行为,因此我的同事很高兴有null检查,而且即使equals()方法存在错误,该方法也会正确执行。我很高兴,因为在开发过程中我将捕获任何bug equals()方法。
Also, you should test your assertion policy by putting in a temporary assertion that will fail, so you can be certain that you are notified, either through the log file or a stack trace in the output stream.
此外,您应该通过放入一个将失败的临时断言来测试断言策略,这样您就可以确定您是通过日志文件或输出流中的堆栈跟踪被通知的。
#4
15
A lot of good answers explaining what the assert
keyword does, but few answering the real question, "when should the assert
keyword be used in real life?"
很多很好的答案解释了assert关键字的作用,但是很少有人回答真正的问题:“断言关键字在现实生活中什么时候应该使用?”
The answer: almost never.
答案是:几乎没有。
Assertions, as a concept, are wonderful. Good code has lots of if (...) throw ...
statements (and their relatives like Objects.requireNonNull
and Math.addExact
). However, certain design decisions have greatly limited the utility of the assert
keyword itself.
断言,作为一个概念,是美妙的。好的代码有很多if(…)抛出…语句(以及它们的亲戚喜欢对象。requireNonNull和Math.addExact)。然而,某些设计决策极大地限制了assert关键字本身的用途。
The driving idea behind the assert
keyword is premature optimization, and the main feature is being able to easily turn off all checks. In fact, the assert
checks are turned off by default.
assert关键字背后的驱动思想是不成熟的优化,主要特性是能够轻松关闭所有检查。事实上,断言检查在默认情况下是关闭的。
However, it is critically important that invariant checks continue to be done in production. This is because perfect test coverage is impossible, and all production code will have bugs which assertions should help to diagnose and mitigate.
然而,在生产中继续进行不变量检查是至关重要的。这是因为完美的测试覆盖是不可能的,并且所有的产品代码都会有错误,断言应该有助于诊断和减轻错误。
Therefore, the use of if (...) throw ...
should be preferred, just as it is required for checking parameter values of public methods and for throwing IllegalArgumentException
.
因此,使用if(…)抛出…应该优先,就像检查公共方法的参数值和抛出IllegalArgumentException所需要的那样。
Occasionally, one might be tempted to write an invariant check that does take an undesirably long time to process (and is called often enough for it to matter). However, such checks will slow down testing which is also undesirable. Such time-consuming checks are usually written as unit tests. Nevertheless, it may sometimes make sense to use assert
for this reason.
偶尔,您可能会想要编写一个不变量检查,它确实需要很长时间来处理(并且经常被调用,这足以让它起作用)。然而,这样的检查将减慢测试,这也是不可取的。这种耗时的检查通常被写成单元测试。然而,出于这个原因,有时使用assert可能是有意义的。
Do not use assert
simply because it is cleaner and prettier than if (...) throw ...
(and I say that with great pain, because I like clean and pretty). If you just cannot help yourself, and can control how your application is launched, then feel free to use assert
but always enable assertions in production. Admittedly, this is what I tend to do. I am pushing for a lombok annotation that will cause assert
to act more like if (...) throw ...
. Vote for it here.
不要仅仅因为它比扔(…)更干净、更漂亮就使用assert。(我很痛苦地说,因为我喜欢干净和漂亮)。如果您不能帮助自己,并且可以控制应用程序的启动方式,那么可以随意使用断言,但在生产中始终支持断言。诚然,这是我倾向于做的。我推动lombok注释,将导致维护像如果(…)....为在这里投票。
(Rant: the JVM devs were a bunch of awful, prematurely optimizing coders. That is why you hear about so many security issues in the Java plugin and JVM. They refused to include basic checks and assertions in production code, and we are continuing to pay the price.)
(Rant: JVM devs是一堆糟糕的、过早优化的程序员。这就是为什么您会在Java插件和JVM中听到这么多安全问题。他们拒绝在生产代码中包含基本的检查和断言,我们将继续为此付出代价。
#5
11
Here's the most common use case. Suppose you're switching on an enum value:
这是最常见的用例。假设您正在打开enum值:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
As long as you handle every case, you're fine. But someday, somebody will add fig to your enum and forget to add it to your switch statement. This produces a bug that may get tricky to catch, because the effects won't be felt until after you've left the switch statement. But if you write your switch like this, you can catch it immediately:
只要你处理好每一个案子,你就没事了。但是总有一天,有人会在你的enum中添加一个图,忘记把它添加到你的switch语句中。这会产生一个可能难以捕获的bug,因为直到您离开switch语句之后才会感觉到影响。但是如果你像这样写你的开关,你可以立刻抓住它:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
#6
9
Assertions are used to check post-conditions and "should never fail" pre-conditions. Correct code should never fail an assertion; when they trigger, they should indicate a bug (hopefully at a place that is close to where the actual locus of the problem is).
断言用于检查后置条件和“不应该失败”前置条件。正确的代码永远不会出错;当它们触发时,它们应该指出一个错误(希望在一个接近问题所在位置的地方)。
An example of an assertion might be to check that a particular group of methods is called in the right order (e.g., that hasNext()
is called before next()
in an Iterator
).
断言的一个示例可能是检查以正确的顺序调用特定的一组方法(例如,在迭代器中的next()之前调用hasNext()))。
#7
6
What does the assert keyword in Java do?
Java中的assert关键字做什么?
Let's look at the compiled bytecode.
让我们看一下编译后的字节码。
We will conclude that:
我们会得出这样的结论::
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
generates almost the exact same bytecode as:
生成几乎完全相同的字节码:
public class Assert {
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
where Assert.class.desiredAssertionStatus()
is true
when -ea
is passed on the command line, and false otherwise.
在命令行上传递-ea时,Assert.class.desiredAssertionStatus()为true,否则为false。
We use System.currentTimeMillis()
to ensure that it won't get optimized away (assert true;
did).
我们使用System.currentTimeMillis()确保它不会被优化(assert true;所做的那样)。
The synthetic field is generated so that Java only needs to call Assert.class.desiredAssertionStatus()
once at load time, and it then caches the result there. See also: What is the meaning of "static synthetic"?
生成合成字段,以便Java只需要在加载时调用一次Assert.class.desiredAssertionStatus(),然后在那里缓存结果。参见:“静态合成”的含义是什么?
We can verify that with:
我们可以用:
javac Assert.java
javap -c -constants -private -verbose Assert.class
With Oracle JDK 1.8.0_45, a synthetic static field was generated (see also: What is the meaning of "static synthetic"?):
在Oracle JDK 1.8.0_45中,生成了一个合成的静态字段(参见:“静态合成”的含义是什么?):
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
together with a static initializer:
与静态初始化器一起:
0: ldc #6 // class Assert
2: invokevirtual #7 // Method java/lang Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #2 // Field $assertionsDisabled:Z
16: return
and the main method is:
主要方法是:
0: getstatic #2 // Field $assertionsDisabled:Z
3: ifne 22
6: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
9: lconst_0
10: lcmp
11: ifeq 22
14: new #4 // class java/lang/AssertionError
17: dup
18: invokespecial #5 // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
We conclude that:
我们得出结论:
- there is no bytecode level support for
assert
: it is a Java language concept - 对于assert没有字节码级支持:它是一个Java语言概念
-
assert
could be emulated pretty well with system properties-Pcom.me.assert=true
to replace-ea
on the command line, and athrow new AssertionError()
. - 断言可以很好地模拟系统属性-Pcom.me。assert=true用于替换命令行上的-ea,以及抛出新的AssertionError()。
#8
6
A real world example, from a Stack-class (from Assertion in Java Articles)
来自堆栈类的真实世界示例(来自Java文章中的断言)
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
#9
4
In addition to all the great answers provided here, the official Java SE 7 programming guide has a pretty concise manual on using assert
; with several spot-on examples of when it's a good (and, importantly, bad) idea to use assertions, and how it's different from throwing exceptions.
除了这里提供的所有优秀答案之外,官方Java SE 7编程指南还提供了使用assert的简明手册;有几个恰当的例子说明什么时候使用断言是一个好(重要的是,坏)的主意,以及它与抛出异常的区别。
链接
#10
3
An assertion allows for detecting defects in the code. You can turn on assertions for testing and debugging while leaving them off when your program is in production.
断言允许检测代码中的缺陷。您可以打开用于测试和调试的断言,而在程序在生产时关闭它们。
Why assert something when you know it is true? It is only true when everything is working properly. If the program has a defect, it might not actually be true. Detecting this earlier in the process lets you know something is wrong.
当你知道这是真的时,为什么要断言某事?只有当一切都正常运转时,它才成立。如果程序有缺陷,它实际上可能不是真的。在这个过程的早期发现这一点让您知道有些事情是错误的。
An assert
statement contains this statement along with an optional String
message.
assert语句和一个可选的字符串消息一起包含该语句。
The syntax for an assert statement has two forms:
assert语句的语法有两种形式:
assert boolean_expression;
assert boolean_expression: error_message;
Here are some basic rules which govern where assertions should be used and where they should not be used. Assertions should be used for:
下面是一些基本规则,它们控制应该在哪里使用断言,在哪里不应该使用断言。断言应用于:
-
Validating input parameters of a private method. NOT for public methods.
public
methods should throw regular exceptions when passed bad parameters.验证私有方法的输入参数。不是公共方法。当传递坏参数时,公共方法应该抛出常规异常。
-
Anywhere in the program to ensure the validity of a fact which is almost certainly true.
在程序的任何地方,确保一个事实的正确性,这几乎是正确的。
For example, if you are sure that it will only be either 1 or 2, you can use an assertion like this:
例如,如果您确定只有1或2,您可以使用如下断言:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
- Validating post conditions at the end of any method. This means, after executing the business logic, you can use assertions to ensure that the internal state of your variables or results is consistent with what you expect. For example, a method that opens a socket or a file can use an assertion at the end to ensure that the socket or the file is indeed opened.
- 在任何方法的末尾验证post条件。这意味着,在执行业务逻辑之后,您可以使用断言来确保变量或结果的内部状态与预期一致。例如,打开套接字或文件的方法可以在末尾使用断言,以确保套接字或文件确实被打开。
Assertions should not be used for:
不应使用断言:
-
Validating input parameters of a public method. Since assertions may not always be executed, the regular exception mechanism should be used.
验证公共方法的输入参数。由于断言可能并不总是被执行,所以应该使用常规异常机制。
-
Validating constraints on something that is input by the user. Same as above.
验证用户输入的内容的约束。与上面一样。
-
Should not be used for side effects.
不应用于副作用。
For example this is not a proper use because here the assertion is used for its side effect of calling of the doSomething()
method.
例如,这不是一个合适的用法,因为这里使用断言的副作用是调用doSomething()方法。
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
The only case where this could be justified is when you are trying to find out whether or not assertions are enabled in your code:
唯一可以证明这一点的情况是,当您试图查明您的代码中是否启用了断言时:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Assertions are enabled")
} else {
System.out.println("Assertions are disabled")
}
#11
1
Assert is very useful when developing. You use it when something just cannot happen if your code is working correctly. It's easy to use, and can stay in the code for ever, because it will be turned off in real life.
Assert在开发时非常有用。如果代码正常工作,就不能使用它。它很容易使用,并且可以永远留在代码中,因为在现实生活中它将被关闭。
If there is any chance that the condition can occur in real life, then you must handle it.
如果在现实生活中有任何可能出现这种情况,那么你必须处理它。
I love it, but don't know how to turn it on in Eclipse/Android/ADT . It seems to be off even when debugging. (There is a thread on this, but it refers to the 'Java vm', which does not appear in the ADT Run Configuration).
我喜欢它,但不知道如何在Eclipse/Android/ADT中打开它。即使在调试的时候,它似乎也是关闭的。(上面有一个线程,但它指的是“Java vm”,它不出现在ADT Run配置中)。
#12
1
Here's an assertion I wrote in a server for a Hibernate/SQL project. An entity bean had two effectively-boolean properties, called isActive and isDefault. Each could have a value of "Y" or "N" or null, which was treated as "N". We want to make sure the browser client is limited to these three values. So, in my setters for these two properties, I added this assertion:
下面是我在服务器上为Hibernate/SQL项目编写的断言。实体bean有两个有效的布尔属性,即isActive和isDefault。每个值都可以有“Y”或“N”或null,被当作“N”。我们希望确保浏览器客户端仅限于这三个值。因此,在我的setter中,这两个属性,我添加了这个断言:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Notice the following.
请注意以下。
-
This assertion is for the development phase only. If the client sends a bad value, we will catch that early and fix it, long before we reach production. Assertions are for defects that you can catch early.
此断言仅适用于开发阶段。如果客户发送了一个错误的值,我们将尽早捕获并修复它,在我们到达生产阶段之前。断言是关于您可以及早发现的缺陷的。
-
This assertion is slow and inefficient. That's okay. Assertions are free to be slow. We don't care because they're development-only tools. This won't slow down the production code because assertions will be disabled. (There's some disagreement on this point, which I'll get to later.) This leads to my next point.
这种断言是缓慢而低效的。没关系。断言是可以慢慢来的。我们不在乎,因为它们只是开发工具。这不会减慢生产代码,因为断言将被禁用。(在这一点上有一些分歧,我稍后会讲到。)这就引出了我的下一个观点。
-
This assertion has no side effects. I could have tested my value against an unmodifiable static final Set, but that set would have stayed around in production, where it would never get used.
这个断言没有副作用。我本来可以用一个不可修改的静态最终集来测试我的值,但是这个集合将会一直存在于生产中,在那里它永远不会被使用。
-
This assertion exists to verify the proper operation of the client. So by the time we reach production, we will be sure that the client is operating properly, so we can safely turn the assertion off.
存在此断言是为了验证客户机的正确操作。因此,当我们到达生产阶段时,我们将确保客户端正在正常运行,因此我们可以安全地关闭断言。
-
Some people ask this: If the assertion isn't needed in production, why not just take them out when you're done? Because you'll still need them when you start working on the next version.
有些人会问:如果在生产过程中不需要这个断言,为什么不直接把它们去掉呢?因为当您开始开发下一个版本时仍然需要它们。
Some people have argued that you should never use assertions, because you can never be sure that all the bugs are gone, so you need to keep them around even in production. And so there's no point in using the assert statement, since the only advantage to asserts is that you can turn them off. Hence, according to this thinking, you should (almost) never use asserts. I disagree. It's certainly true that if a test belongs in production, you should not use an assert. But this test does not belong in production. This one is for catching a bug that's not likely to ever reach production, so it may safely be turned off when you're done.
有些人认为您不应该使用断言,因为您永远无法确定所有的bug都消失了,因此您需要将它们保留在产品中。因此,使用assert语句没有任何意义,因为断言的惟一好处是可以关闭它们。我不同意。当然,如果测试属于生产环境,则不应该使用assert。但是这个测试不属于生产。这个程序是用来捕获一个不太可能实现生产的bug,所以当您完成时,它可以安全地关闭。
BTW, I could have written it like this:
顺便说一句,我可以这样写:
assert value == null || value.equals("Y") || value.equals("N") : value;
This is fine for only three values, but if the number of possible values gets bigger, the HashSet version becomes more convenient. I chose the HashSet version to make my point about efficiency.
这只适用于三个值,但是如果可能值的数量变大,HashSet版本就变得更方便了。我选择HashSet版本是为了说明效率。
#13
1
Assertions are disabled by default. To enable them we must run the program with -ea
options (granularity can be varied). For example, java -ea AssertionsDemo
.
默认情况下禁用断言。要启用它们,我们必须使用-ea选项运行程序(粒度可以变化)。例如,java -ea AssertionsDemo。
There are two formats for using assertions:
使用断言有两种格式:
- Simple: eg.
assert 1==2; // This will raise an AssertionError
. - 简单:如。维护1 = = 2;//这将引发断言错误。
- Better:
assert 1==2: "no way.. 1 is not equal to 2";
This will raise an AssertionError with the message given displayed too and is thus better. Although the actual syntax isassert expr1:expr2
where expr2 can be any expression returning a value, I have used it more often just to print a message. - 更好:断言1= 2:“没门。1不等于2"这将引发一个AssertionError,并显示所显示的消息,因此更好。虽然实际的语法是assert expr1:expr2,其中expr2可以是任何返回值的表达式,但我更常用它来打印消息。
#14
0
To recap (and this is true of many languages not just Java):
总结一下(这不仅适用于Java,也适用于许多语言):
"assert" is primarily used as a debugging aid by software developers during the debugging process. Assert-messages should never appear. Many languages provide a compile-time option that will cause all "asserts" to be ignored, for use in generating "production" code.
“assert”主要用于软件开发人员在调试过程中的调试辅助。Assert-messages就不应该出现。许多语言提供了编译时选项,该选项将导致忽略所有的“断言”,以便用于生成“生产”代码。
"exceptions" are a handy way to handle all kinds of error conditions, whether or not they represent logic errors, because, if you run into an error-condition such that you cannot continue, you can simply "throw them up into the air," from wherever you are, expecting someone else out there to be ready to "catch" them. Control is transferred in one step, straight from the code that threw the exception, straight to the catcher's mitt. (And the catcher can see the complete backtrace of calls that had taken place.)
“例外”是一个方便的方式来处理各种各样的错误条件,是否代表逻辑错误,因为,如果你遇到一个错误条件,你不能继续,您可以简单地“扔到空中,“无论你在哪里,希望有人也准备“捕获”它们。控制在一步中转移,直接从抛出异常的代码,直接到捕手的手套。(捕鲸者可以看到所发生的全部通话记录。)
Furthermore, callers of that subroutine don't have to check to see if the subroutine succeeded: "if we're here now, it must have succeeded, because otherwise it would have thrown an exception and we wouldn't be here now!" This simple strategy makes code-design and debugging much, much easier.
此外,该子例程的调用者不必检查子例程是否成功:“如果我们现在在这里,它一定成功了,否则它会抛出一个异常,我们现在就不会在这里了!”这个简单的策略使代码设计和调试更加容易。
Exceptions conveniently allow fatal-error conditions to be what they are: "exceptions to the rule." And, for them to be handled by a code-path that is also "an exception to the rule ... "fly ball!"
异常可以方便地允许致命错误条件是它们本身:“规则的异常”。而且,对于它们,代码路径也是“规则的例外……”“高飞球!”
#15
0
Assertion are basically used to debug the application or it is used in replacement of exception handling for some application to check the validity of an application.
断言主要用于调试应用程序,或者用于替换某些应用程序的异常处理,以检查应用程序的有效性。
Assertion works at run time. A simple example, that can explain the whole concept very simply, is herein - What does the assert keyword do in Java? (WikiAnswers).
断言在运行时工作。一个简单的例子,可以很简单地解释整个概念——在Java中,assert关键字是干什么的?(WikiAnswers)。
#16
0
Basically, "assert true" will pass and "assert false" will fail. Let's looks at how this will work:
基本上,“assert true”将通过,“assert false”将失败。让我们看看它是如何工作的:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
#17
-8
assert
is a keyword. It was introduced in JDK 1.4. The are two types of assert
s
断言是一个关键词。它是在JDK 1.4中引入的。有两种类型的断言
- Very simple
assert
statements - 非常简单的断言语句
- Simple
assert
statements. - 简单的断言语句。
By default all assert
statements will not be executed. If an assert
statement receives false, then it will automatically raise an assertion error.
默认情况下,不会执行所有assert语句。如果断言语句接收到false,那么它将自动引发断言错误。