介绍
在本实验中,你将学习 Java 中的断言(assertions)。你将了解如何创建断言以及何时使用它们。断言用于测试代码中的假设,主要在软件的测试阶段使用。
在本实验中,你将学习 Java 中的断言(assertions)。你将了解如何创建断言以及何时使用它们。断言用于测试代码中的假设,主要在软件的测试阶段使用。
让我们创建一个简单的断言来测试一个数字是否为偶数。我们将假设这个数字是偶数,并使用一个偶数来编写断言。然后,我们将改变这个数字并运行代码。我们应该会得到一个 AssertionError
。
public class AssertionsLab {
public static void main(String[] args) {
int number = 4;
assert (number % 2) == 0;
System.out.println("Number is even");
// 将 number 变量的值改为奇数
number = 3;
assert (number % 2) == 0;
System.out.println("Number is even");
}
}
默认情况下,Java 中的断言是禁用的。我们可以通过命令行选项来启用断言。
让我们使用 -ea
选项来启用断言并运行代码。
java -ea AssertionsLab
代码应该会打印 "Number is even",然后抛出一个 AssertionError
。
现在,让我们使用 -da
选项禁用断言并再次运行代码。
java -da AssertionsLab
代码应该会打印两次 "Number is even",而不会抛出任何异常。
断言也可以用于测试方法的输入。让我们创建一个 divide
方法,该方法接收两个参数并返回第一个参数除以第二个参数的商。我们将假设第二个参数不为零,并创建一个断言来检查这一点。
public class AssertionsLab {
public static void main(String[] args) {
int a = 10;
int b = 5;
int result = divide(a, b);
System.out.println("Result: " + result);
// 将 b 的值改为零
b = 0;
result = divide(a, b);
System.out.println("Result: " + result);
}
private static int divide(int a, int b) {
assert b != 0 : "Cannot divide by zero";
return a / b;
}
}
我们可以使用断言进行调试和测试。假设我们有一个程序,它读取文件并返回其中的第一个非零数字。为了测试这个程序,让我们创建一个包含三个数字的输入文件。
echo "0\n3\n0" > input.txt
让我们编写一个程序,读取文件并返回其中的第一个非零数字。然后,我们将创建一个断言来测试程序是否返回了正确的输出。
import java.io.File;
import java.io.FileNotFoundException;
+ import java.util.Scanner;
public class AssertionsLab {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner = new Scanner(new File("input.txt"));
int number = 0;
while (scanner.hasNext()) {
number = scanner.nextInt();
if (number != 0) {
break;
}
}
assert number == 3 : "Incorrect number read from file";
System.out.println("First non-zero number: " + number);
}
}
断言不适合用于验证公共方法的参数。这些断言在运行时可能会被禁用,从而导致意外行为。
public class AssertionsLab {
public static void main(String[] args) {
int negativeNumber = -1;
printPositiveNumber(negativeNumber);
}
public static void printPositiveNumber(int number) {
assert (number > 0) : "Not a valid positive number";
System.out.println("Positive number: " + number);
}
}
我们可以为断言添加信息性消息,使其更具信息性,并在失败时提供更好的反馈。现在我们将修改之前代码中的断言,以包含一条信息性消息。
public class AssertionsLab {
public static void main(String[] args) {
int number = -1;
assert (number > 0) : "Negative number found";
System.out.println("Number is positive: " + number);
}
}
当代码执行时,消息 "Negative number found" 将会显示。
断言的主要目的是在测试软件时发现错误。然而,如果断言本身破坏了代码,那就会成为问题。例如,瞬态网络错误或系统上的时序问题可能导致断言失败。此外,如果我们使用断言来验证公共方法的输入,我们可能会让系统面临无效和恶意输入的风险。
避免断言负面影响的一种方法是谨慎使用它们。仅在那些在良好设计的系统中永远不应该发生的情况下使用断言。
public class AssertionsLab {
public static void main(String[] args) {
double result = squareRoot(4);
System.out.println("Square root: " + result);
double negativeNumber = -4;
result = squareRoot(negativeNumber);
System.out.println("Square root: " + result);
}
public static double squareRoot(double number) {
assert number >= 0 : "Number should be non-negative";
return Math.sqrt(number);
}
}
在使用断言时,避免副作用非常重要。我们应该避免在断言中修改变量。相反,表达式应仅用于检测问题情况并提供更多诊断信息。
public class AssertionsLab {
public static void main(String[] args) {
int firstNumber = 1;
int secondNumber = 2;
assert (firstNumber = secondNumber) == 0 : "Values are not equal";
System.out.println("Values are equal");
}
}
我们可以使用断言来检查 switch 语句是否覆盖了所有可能的情况。让我们创建一个 switch 语句,根据数字返回对应的星期名称。我们假设数字在 0 到 6 的范围内,并创建一个断言来检查这一点。
public class AssertionsLab {
public static void main(String[] args) {
int dayNumber = 2;
String day = getDayName(dayNumber);
System.out.println("Day: " + day);
// set dayNumber to an invalid number
dayNumber = 10;
day = getDayName(dayNumber);
System.out.println("Day: " + day);
}
public static String getDayName(int dayNumber) {
String day;
switch (dayNumber) {
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
case 6:
day = "Saturday";
break;
default:
assert false : "Invalid day number";
}
return day;
}
}
恭喜!你已经完成了 Java 断言实验。你可以在 LabEx 中练习更多实验来提升你的技能。