如何在Java中最佳利用断言?

时间:2020-02-23 14:33:56  来源:igfitidea点击:

本文向我们介绍Java断言一个简单而重要的概念,并通过编程演示对其进行跟进。

是否想测试程序中的假设是否正确?
好吧,我们可以使用Java中的断言语句来实现。
我们可以使用assert关键字创建断言,以使我们可以在程序中测试假设。

让我们举个例子。
ABC中的雇员的年龄不能为负数。
我们可以为此使用断言,以确保员工的年龄不是负数。

让我们再举一个例子。
如果方法计算粒子的速度,则假设是粒子的速度小于光速。
因此,要测试此假设,可以在Java中使用断言语句。

语法

断言语句有两种形式:

assertexpression1;

其中

表达式1是布尔表达式。

断言expression1:expression2;

在这种形式中,表达式1是布尔表达式,而表达式2具有将与表达式1比较的值。

现在,我们可能会问我们为程序选择哪种形式?
当程序中包含有助于我们诊断程序中的错误或者故障的其他信息时,可以使用第二种形式。

在Java 1.4之前,我们可能已经使用关键字" assert"来命名变量,方法,函数等。
对于较新版本的JVM,这可能会导致命名冲突,因此我们需要对此有所注意。

为什么需要断言?

我们可能会认为Java中的断言语句可能是不必要的。
对于小型程序,我们可能会发现它不必要。
但是,当涉及到具有复杂逻辑的大型程序时,这些断言语句会派上用场。

断言语句的主要用途是用于调试和测试。
如果断言语句中有任何故障,那么JVM将抛出一个标为AssertionError的错误。
如我们所见,这提供了一种检测和纠正程序错误的有效方法。

除了调试和测试外,断言语句还使代码更具可读性。
让我们举个例子:

以下代码我们验证某些条件,这些条件可能会阻止应用程序正常运行。

Connection conn = getConnection();
if(conn == null) {
throw new RuntimeException("Connection is null");
}

使用单个断言语句,我们基本上可以消除" if and throw"语句,如下所示:

Connection conn = getConnection();
assert conn != null;

启用和禁用Java断言

由于Java断言使用assert关键字,因此我们无需导入软件包或者库。
如前所述,可以将assert关键字用于变量,方法和函数。
为了向后兼容,并且为了避免潜在的命名冲突,JVM默认情况下禁用断言验证。
必须明确启用断言。
我们可以使用命令行参数(-enableassertions)或者使用其简写(-ea)来实现。

让我们考虑一些示例:

java -ea com.baeldung.assertion.Assertion

上面启用了对类的断言。

java -ea:com.baeldung.assertion ... com.baeldung.assertion.Assertion

我们也可以为特定的包和类启用断言。
在上面的示例中显示了这一点,其中我们为com.baeldung.assertion包中的类启用了断言。

现在我们已经了解了启用断言的方法,下面让我们看看如何禁用断言。
与启用断言非常相似,可以使用命令行参数(-disableassertions)或者其速记(-da)来禁用特定的包和类来禁用。

如何使用Java断言?

在程序中实现assert关键字和一个布尔条件需要两件事。
让我们以代码段为例:

public void setup()
{
Connection conn = getConnection();
assert conn != null;
}

我们还可以将字符串用于上述断言,如下所示:

public void setup() 
{
Connection conn = getConnection();
assert conn != null : "Connection is null";
}

在上面的代码片段中,如果存在AssertionError,则将使用字符串来构造错误。

在上述两种情况下,代码都会检查与外部源的连接是否返回非null值。
如果该值为null,则JVM将自动引发AssertionError。

在第二个示例中,当出现AssertionError时,我们使用的字符串将显示在堆栈跟踪中。
当我们尝试调试程序时,此添加信息将很有用。
这些详细的消息将修复可能导致断言失败的错误。
因此,当我们在启用了断言的情况下运行该类时,结果将类似于以下内容:

线程" main"中的异常java.lang.AssertionError:com.baeldung.assertion.Assertion.setup(Assertion.java:15)处的连接为com.baeldung.assertion.Assertion.main(Assertion.java:10)处的连接为空

让我们考虑一个简单的示例:

import java.util.Scanner;
class AssertionExample
{
public static void main( String args[] )
{
Scanner scanner = new Scanner( System.in );
System.out.print("Enter your age ");
int value = scanner.nextInt();
assert value>=18:"Not valid";
System.out.println("value is "+value);
}
}

现在我们已经掌握了代码,现在该运行它了。
由于默认情况下断言是禁用的,因此我们必须启用它们。

我们可以使用以下代码编译以上代码:javac AssertionExample.java

然后可以使用以下命令运行它:java -ea AssertionExample

上面代码的输出是:

输入年龄11

线程" main"中的异常java.lang.AssertionError:无效

如我们所见,我们给出了11作为年龄值。
该程序不将其视为合法值。
因此,我们将看到一个AssertionError。

其中不使用断言?

虽然在包括内部不变量,控制流不变量,前提条件,后置条件和类不变量的情况下具有断言是很好的,但在某些情况下不应使用断言。

让我们进一步探讨:

用于公共方法中的参数检查

我们应该了解,参数检查是已发布的规范或者方法合同的一部分。
无论是否启用断言,都必须遵循这些规则。

使用断言进行操作

默认情况下,断言被禁用。
程序不应假定断言语句中的布尔表达式将始终被求值。

让我们举个例子,说明这可能会影响程序。
假设我们要从名称列表中删除所有null元素,并且我们知道列表中包含null元素。

断言names.remove(null);

如果启用了断言,以上代码段将起作用。
但是,如果断言被禁用,它将失败,因为代码不会删除任何空元素。
要解决此问题,我们可以在程序中使用以下代码段:

布尔值nullsRemoved = names.remove(null);断言nullsRemoved;

即使禁用断言,以上代码段也将删除空值。