原文: https://www.programiz.com/java-programming/assertions

在本教程中,我们将借助示例学习 Java 断言(Java 断言)。

Java 断言通过测试代码来检测错误,我们认为这是正确的。

使用assert关键字进行断言。

其语法为:

  1. assert condition;

在这里,condition是一个布尔表达式,我们假定在程序执行时为true


启用断言

默认情况下,断言在运行时被禁用并被忽略。

为了启用断言,我们使用:

  1. java -ea:arguments

要么

  1. java -enableassertions:arguments

启用断言且条件为true时,程序将正常执行。

但是,如果在启用断言的情况下条件求值为false,则 JVM 会抛出AssertionError,程序将立即停止。


示例 1:Java 断言

  1. class Main {
  2. public static void main(String args[]) {
  3. String[] weekends = {"Friday", "Saturday", "Sunday"};
  4. assert weekends.length == 2;
  5. System.out.println("There are " + weekends.length + " weekends in a week");
  6. }
  7. }

输出

  1. There are 3 weekends in a week

我们得到上面的输出,因为该程序没有编译错误,并且默认情况下,断言被禁用。

启用断言后,我们得到以下输出:

  1. Exception in thread "main" java.lang.AssertionError

断言声明的另一种形式

  1. assert condition : expression;

在这种形式的断言语句中,将表达式传递到AssertionError对象的构造器。 如果条件为false,则此表达式的值显示为错误的详细信息。

详细消息用于捕获和传输断言失败的信息,以帮助调试问题。


示例 2:带有表达式示例的 Java 断言

  1. class Main {
  2. public static void main(String args[]) {
  3. String[] weekends = {"Friday", "Saturday", "Sunday"};
  4. assert weekends.length==2 : "There are only 2 weekends in a week";
  5. System.out.println("There are " + weekends.length + " weekends in a week");
  6. }
  7. }

输出

  1. Exception in thread "main" java.lang.AssertionError: There are only 2 weekends in a week

从上面的示例中可以看到,表达式被传递给AssertionError对象的构造器。 如果我们的假设是false并且启用了断言,则会抛出异常并附带一条适当的消息。

此消息有助于诊断和修复导致断言失败的错误。


对特定的类和包启用断言

如果我们不向断言命令行开关提供任何参数,

  1. java -ea

这将在除系统类之外的所有类中启用断言。

我们还可以使用参数为特定的类和包启用断言。 可以提供给这些命令行开关的参数为:

启用类名中的断言

为了对程序Main的所有类启用断言,

  1. java -ea Main

要仅启用一个类,

  1. java -ea:AnimalClass Main

这仅允许在Main程序的AnimalClass中声明。

启用包名称中的断言

要仅启用包com.animal及其子包的断言,

  1. java -ea:com.animal... Main

启用未命名包中的断言

要在当前工作目录中的未命名包中启用断言(当我们不使用package语句时)。

  1. java -ea:... Main

启用系统类中的断言

为了在系统类中启用断言,我们使用不同的命令行开关:

  1. java -esa:arguments

OR

  1. java -enablesystemassertions:arguments

可以提供给这些开关的参数是相同的。


禁用断言

要禁用断言,我们使用:

  1. java -da arguments

OR

  1. java -disableassertions arguments

要禁用系统类中的断言,我们使用:

  1. java -dsa:arguments

OR

  1. java -disablesystemassertions:arguments

禁用断言时可以传递的参数与启用断言时相同。


断言的优点

  1. 快速高效地检测和纠正错误。
  2. 断言检查仅在开发和测试期间进行。 它们会在运行时自动删除在生产代码中,以免减慢程序的执行速度。
  3. 它有助于删除样板代码并使代码更具可读性。
  4. 重构和优化代码,以增强其正确运行的信心。

何时使用断言

1.无法访问的代码

无法访问的代码是当我们尝试运行该程序时不会执行的代码。 使用断言来确保无法访问的代码实际上是不可访问的。

让我们举个例子。

  1. void unreachableCodeMethod() {
  2. System.out.println("Reachable code");
  3. return;
  4. // Unreachable code
  5. System.out.println("Unreachable code");
  6. assert false;
  7. }

让我们再举一个不带默认大小写的switch语句示例。

  1. switch (dayOfWeek) {
  2. case "Sunday":
  3. System.out.println("It’s Sunday!");
  4. break;
  5. case "Monday":
  6. System.out.println("It’s Monday!");
  7. break;
  8. case "Tuesday":
  9. System.out.println("It’s Tuesday!");
  10. break;
  11. case "Wednesday":
  12. System.out.println("It’s Wednesday!");
  13. break;
  14. case "Thursday":
  15. System.out.println("It’s Thursday!");
  16. break;
  17. case "Friday":
  18. System.out.println("It’s Friday!");
  19. break;
  20. case "Saturday":
  21. System.out.println("It’s Saturday!");
  22. break;
  23. }

上面的switch语句指示星期几只能是上述 7 个值之一。 没有默认情况意味着程序员认为这些情况之一将始终被执行。

但是,在某些假设实际上是错误的情况下,可能尚未考虑某些情况。

应该使用断言来检查此假设,以确保未达到默认切换条件。

  1. default:
  2. assert false: dayofWeek + " is invalid day";

如果dayOfWeek的值不是有效天数,则会抛出AssertionError


2.记录假设

为了记录其基本假设,许多程序员使用注释。 让我们举个例子。

  1. if (i % 2 == 0) {
  2. ...
  3. } else { // We know (i % 2 == 1)
  4. ...
  5. }

请改用断言。

随着程序的增长,注释可能会过时和不同步。 但是,我们将不得不更新assert语句; 否则,它们也可能因有效条件而失败。

  1. if (i % 2 == 0) {
  2. ...
  3. } else {
  4. assert i % 2 == 1 : i;
  5. ...
  6. }

什么时候不使用断言

1.公共方法中的参数检查

用户可以提供公共方法中的参数。

因此,如果使用断言来检查这些参数,则条件可能会失败并导致AssertionError

不要使用断言,而要导致适当的运行时异常并处理这些异常。


2.计算影响程序运行的表达式

不要调用方法或求值可能在断言条件下影响程序操作的异常。

让我们以列表weekdays为例,该列表包含一周中所有天的名称。

  1. ArrayList<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ));
  2. ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" ));
  3. assert weekdays.removeAll(weekends);

在这里,我们试图从工作日的ArrayList中删除元素SaturdaySunday

如果启用了断言,则程序可以正常运行。 但是,如果禁用了断言,则不会删除列表中的元素。 这可能会导致程序失败。

而是将结果分配给变量,然后使用该变量进行断言。

  1. ArrayList<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ));
  2. ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" ));
  3. boolean weekendsRemoved = weekdays.removeAll(weekends);
  4. assert weekendsRemoved;

这样,无论断言是启用还是禁用,我们都可以确保从weekdays中删除所有weekends。 结果,它不会影响将来的程序操作。