HOWTO · Java
Java 中的 assert 关键字
本文介绍何时以及如何使用 Java assert 关键字。
本页内容
Java 的 assert 关键字用于检查程序员的假设,而 JVM 默认会关闭断言。启动程序时添加 -ea 即可启用断言。启用断言后,如果条件计算结果为 false,Java 会抛出 AssertionError;否则程序会继续执行。断言适用于检查开发期间应当成立的内部假设,不应依赖断言来执行每次运行都必须完成的应用行为。
在 Java 中将 assert 用作布尔条件
基本形式是 assert condition;,其中 condition 必须是布尔表达式。启用断言后,如果表达式为 false,Java 会在断言语句处抛出 AssertionError。关闭断言时,JVM 会跳过该断言,也不会计算其中的条件。因此,条件不能执行程序依赖的工作。
下面这个完整的类会检查一个计数,并打印简短结果。
public class JavaAssertCheck {
public static void main(String[] args) {
String[] names = {"John", "Mary", "David"};
assert names.length == 3;
System.out.println("Name count: " + names.length);
}
}
编译此类,然后使用 java -ea JavaAssertCheck 运行,以启用检查。不添加 -ea 运行时,断言会被跳过。如果将预期计数改为与数组长度不符的值并启用断言,程序会在断言处停止并抛出 AssertionError。
使用 assert condition : expression 添加诊断消息
如果希望失败时附带上下文,可以使用 assert condition : expression。只有在启用了断言且条件为 false 时,才会计算该表达式;其值会成为所抛出 AssertionError 的详细消息。例如,assert names.length == expected : "Expected " + expected + " names, got " + names.length; 会指出这两个计数。表达式应避免副作用,因为条件通过或断言关闭时都不会计算它。
使用 assert 标记意外分支
如果程序逻辑认为某个运行时分支不应到达,可以用断言标记该分支。Java 会拒绝放在无条件 return 之后的语句,因此应将断言放进编译器无法证明不可达的分支中:
public class StatusLabel {
static String label(int status) {
if (status == 0) {
return "ready";
} else if (status == 1) {
return "busy";
} else {
assert false : "Unexpected status: " + status;
return "unknown";
}
}
public static void main(String[] args) {
System.out.println(label(0));
}
}
启用断言时,如果执行到最后一个分支,就会抛出带有状态信息的 AssertionError。关闭断言时,程序会执行后备的 return,因此这里的断言只是诊断辅助,不能作为必需的控制流程。
安全地使用断言检查内部不变量
断言适合记录由程序自身建立的不变量,例如内部计算后某个值仍处于指定范围内。开发期间,如果这类假设被违反,断言有助于更容易定位问题。
不要用断言验证传入公共方法的参数:无论 JVM 选项如何,调用方都需要得到明确的验证结果。同样,不要把必需的应用工作放进断言中,因为关闭断言时其条件不会执行。基于同样的原因,断言表达式也应避免副作用。只要程序在生产环境中必须始终以一致方式响应,就应使用常规验证和控制流程。