如何在Java中最佳利用断言?
本文向我们介绍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;
即使禁用断言,以上代码段也将删除空值。