Java中的关键字assert是什么意思?

8
我在GWT代码中看到过类似这样的内容:

assert display instanceof Widget : "display必须扩展Widget";

这段代码涉及IT技术,它的意思是要求变量"display"必须是"Widget"类的子类。如果不是,就会抛出错误信息:"display必须扩展Widget"。
5个回答

13
assert关键字像其名称所示,对代码进行了一项断言。它用于指定始终为真的某些内容——或者至少应该是真的!assert关键字后面跟着一个布尔值(truefalse),或者在运行时要评估返回布尔值的表达式。
assert true;
assert 1 == 1;

如果由于任何原因布尔表达式计算结果为false,则会抛出一个AssertionError

// this will throw an AssertionError:
int x = 1;
assert x == 2;
当您使用 `assert` 时,您会对程序在给定点上的状态做出明确的陈述,这可以使读者更容易跟随您的代码。
有一种名为“按契约编程”的编程范式,在该范式中,代码片段对必须满足的前提条件以及执行后保证成立的后置条件进行声明。您可以使用 `assert` 关键字来实现这一点。
例如,如果您编写了一个计算数字平方根的方法,它只适用于大于或等于零的数字,并且结果保证满足相同的条件:
public double sqrt(final double x) {
    assert x >= 0 : "Cannot calculate the square root of a negative number!"
    double result = ...;
    assert result >= 0 : "Something went wrong when calculating the square root!"
    return result;
}

断言最有趣的方面是您可以要求编译器从字节码中删除它们(通过-disableassertion参数),以便在生产时不会出现任何运行时性能损失。因此,极其重要的是,要评估的表达式不会引起副作用,也就是说,该表达式应该像纯数学函数一样。否则,如果编译器删除了您的断言,则程序的行为可能会发生变化。

最后,如果断言被编译到字节码中,它们可以被软件读取,该软件将自动生成测试,试图破坏您的代码。这可能有助于更早地发现错误!


1
实际上,它会抛出一个 AssertionError,它是 Error 的子类,而 Error 又是 Throwable 的子类。ExceptionThrowable 的另一个子类,但具有不同的语义。你可以将 Error 视为比 Exception 更糟糕的东西。异常存在的目的是让你将“主要代码”与处理运行时可能发生的问题的代码(例如 IOException)分开。当发生更严重且通常无法恢复的情况时,例如 OutOfMemoryError 或 StackoverflowError 时,就会抛出错误。 - Bruno Reis
1
你的目标是让你的代码永远不会抛出 AssertionError,因为这意味着你的代码没有被正确使用(即必须满足的前提条件并没有完全满足!)。 - Bruno Reis
1
如果你想在Java中尝试契约式编程,一个起点可以是Google的Guava库。它包含一个名为Preconditions的类,其中有静态方法接受表达式和字符串,并且几乎像assert关键字一样工作。主要区别是:(1)Guava将抛出未经检查的异常而不是AssertionError;(2)这些方法具有更多语义化的名称,例如Preconditions.checkNotNull(myParameter);(3)它们不能被编译器自动删除。 - Bruno Reis
1
关于你上一条评论:是的,完全正确! - Bruno Reis
1
你只需要向编译器传递一个参数:javac -disableassertion MyClass.java。该参数本身可以接受参数,因此您可以有选择地在某些类上禁用断言,并在其他类上启用它们。 - Bruno Reis
显示剩余4条评论

3
Assert关键字是在1.4版本中引入的(单击该链接获取完整描述)。它是一种快捷方式,用于在运行时抛出异常,如果条件不满足。

将其视为

assert condition : message

作为

if ( ! condition ) {
    throw new AssertionError ( message ) ;
}

这个想法是为开发人员(在您的情况下是GWT API用户)提供一种简单的方法来检测常见的错误/陷阱。

assert语句被引入时,它成为了一个保留字,并且当旧代码重新编译为I.4时会导致一些编译问题。特别是对于JUnit测试套件,其中有一个非常常用的assert()方法。JUnit通过将assert替换为assertTrue()来做出反应。


0
这意味着如果 display 不是 Widget 类型的对象,你将会得到一个断言错误(AssertionError),并且会附带一个断言信息字符串。断言语句对于调试非常有帮助。

所以这只是在调试时有用,与运行时代码执行无关,对吧? - user562350
1
嗯,如果你的意思是它不应该用于控制流程,那么这可能不太合适。如果你的断言在最终产品中被证明不正确,我认为那意味着你某个地方出了很大的问题! - Owen

0
assert关键字用于简化用户自定义异常的处理。如果要定义一个用户自定义异常,我们必须首先定义异常条件并创建我们自己的异常类,然后在程序中抛出它。 但是从Java 1.5开始,我们有了assert关键字,只需编写assert(condition),如果条件为真,则执行程序的其他部分;否则,它会创建AssertionError类的对象,我们需要处理它。 因此不需要定义我们自己的用户自定义错误。

0

以下文字(重点在我)清晰地解释了各种形式的断言:


断言语句有两种形式。
第一种更简单的形式是:
assert Expression1;
其中Expression1是一个布尔表达式。当系统运行断言时,它会评估Expression1,如果为false,则抛出一个没有详细信息的AssertionError。
断言语句的第二种形式是:
assert Expression1: Expression2; (你的例子属于这里)
其中:Expression1是一个布尔表达式。Expression2是一个具有值的表达式。(它不能是声明为void的方法的调用。)使用这个版本的assert语句来为AssertionError提供详细信息。系统将Expression2的值传递给适当的AssertionError构造函数,该构造函数使用该值的字符串表示作为错误的详细信息。
此外,请参考以下Oracle链接获取详细信息: http://docs.oracle.com/javase/7/docs/technotes/guides/language/assert.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接