Java 断言编程第一部分
介绍
您可能在通过JUnit等框架或AssertJ等第三方断言库进行单元测试时使用过断言方法。
但是你知道 Java 有一个内置的断言机制吗?如果你知道,你以前用过它吗?
Java 的断言早在 Java 1.4 中就已引入,与单元测试框架的断言方法一样,它们使用布尔表达式,如果计算结果为 false,则抛出异常。
但是,它们可以在代码中的任何位置使用(由于一些良好的做法而有一些限制)并且具有与其他断言方法不同的语义。
断言会检验您认为真实的事情。
它可能是你认为不可能发生的事情、执行一段代码后必须出现的事情、或者是你的代码必须为真的事情。
这听起来可能是一个简单的概念,但它是理解和正确使用断言的关键。
在本系列指南中,我将向您展示如何使用 Java 断言机制、启用和禁用断言的语法和选项、良好的断言实践、使用断言的契约式设计编程风格,以及断言如何区分异常和单元测试。
使用断言
让我们从如何使用断言的基础开始。
断言使用保留的assert关键字。其语法如下:
assert booleanExpression;
以下是一个例子:
private double calculateInterest(double amount) {
assert amount > 0 && amount <= 1_000;
double interest = 0.0;
// calculate interest
return interest;
}
如果条件计算结果为false ,则会抛出java.lang.AssertionError类型的异常。
这意味着上面的例子等同于下面的例子:
private double calculateInterest(double amount) {
if(amount > 0 && amount < 1_000) {
throw new AssertionError();
}
double interest = 0.0;
// calculate interest
return interest;
}
为什么AssertionError是Error的子类而不是RuntimeException的子类?
因为我们不应该捕获Error及其子类。
尝试从断言错误中恢复是没有意义的。这样的错误意味着程序没有在程序员假设的条件下运行。这很可能会导致继续执行导致更多错误。
因此错误将导致程序停止,并打印堆栈跟踪,例如:
Exception in thread "main" java.lang.AssertionError
at com.example.AssertTest.calculateInterest(AssertTest.java:6)
at com.example.AssertTest.main(AssertTest.java:16)
那可能不是很有用。
但是,assert 语句也可以接收消息:
assert booleanExpression : "Message about the error";
例如,如果以下断言失败:
private double calculateInterest(double amount) {
assert
amount > 0 && amount < 1_000
:
"Amount should be between 0 and 1,000: "
+ amount;
// ...
}
类似下面的内容将被打印到标准输出:
Exception in thread "main" java.lang.AssertionError: Amount should be between 0 and 1,000: -11.0
at com.example.AssertTest.calculateInterest(AssertTest.java:6)
at com.example.AssertTest.main(AssertTest.java:16)
再次强调,上面的例子等同于:
if(amount > 0 && amount < 1_000) {
throw new AssertionError(
"Amount should be between 0 and 1,000: "
+ amount
);
}
// ...
}
大多数情况下,你会使用String,但是如果你查看AssertionError的构造函数,你会发现它也可以采用其他可以转换为字符串的类型:
AssertionError(boolean detailMessage)
AssertionError(char detailMessage)
AssertionError(double detailMessage)
AssertionError(float detailMessage)
AssertionError(int detailMessage)
AssertionError(long detailMessage)
AssertionError(Object detailMessage)
AssertionError(String message, Throwable cause)
这意味着如果这对你来说足够了,你可以使用类似如下的方法:
private double calculateInterest(double amount) {
assert amount > 0 && amount < 1_000 : amount;
// ...
}
如果布尔表达式的计算结果为true,则什么也不会发生。
但是,默认情况下断言不启用。因此,即使断言失败,如果您不使用特殊标志运行程序,也不会发生任何事情。
使用-ea或enableassertions标志可以启用断言:
java –ea AssertTest
// Or
java –enableassertions AssertTest
这将在我们程序中除 Java 类(系统类)之外的所有类中启用断言。
如果您想在 Java 类中启用断言,您可以使用-esa或enablesystemassertions标志:
java –esa AssertTest
// Or
java –enablesystemassertions AssertTest
您还可以只为一个类启用断言:
java –ea:com.example.MyOtherClass AssertTest
或者在特定命名的包及其任何子包中:
java –ea:com.example... AssertTest
或者在当前工作目录中的默认包中:
java –ea:... AssertTest
还有一个禁用断言的选项:
java –da AssertTest
// Or
java –disableassertions AssertTest
以及在 Java 类中禁用断言的相应选项:
java –dsa AssertTest
// Or
java –disablesystemassertions AssertTest
您可能想知道,如果默认情况下断言是禁用的,为什么我们还会有这个选项?
好吧,您可以使用相同的ea和esa标志选项来禁用一个类或整个包。
你也可以将它们组合起来。例如,你可以在com.example包中的所有类中启用断言,但com.example.Utils类除外:
java –ea:com.example... -da:com.example.Utils AssertTest
契约式设计风格和断言
Java 的断言机制可用于非正式的契约式设计编程风格。
契约式设计是一种软件设计方法,该方法将软件视为一组组件,这些组件的交互基于相互定义的义务或契约,其形式为:
- 可接受和不可接受的输入和返回值或类型
- 可能发生的错误和异常情况
- 副作用
- 先决条件
- 后置条件
- 不变量
这个概念是由Bertrand Meyer构思出来的,他基于这个概念以及其他面向对象编程的概念设计了Eiffel 编程语言。
例如,在 Eiffel 中,您可以使用以下语法来编写例程:
processElement (e : ELEMENT) is
require
not e.empty
do
-- Perform the operation
ensure
e.is_processed
end
与 assert 类似,require子句检查输入或先决条件,而Ensure子句检查输出或后置条件。这两个条件都是与此例程相关的合同的一部分。
但是我们也可以设置一些必须始终适用于整个类的条件(例如在调用某个方法之前和之后),而不仅仅是在某个特定时刻。这些被称为类不变量:
invariant
element_count > 0
您可以将不变量视为一种条件,它既是先决条件,又是后置条件。
这样,Eiffel 的 IDE就可以以文本格式提供该类的简短形式<font
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~