# Java 断言 > 原文: [https://www.programiz.com/java-programming/assertions](https://www.programiz.com/java-programming/assertions) #### 在本教程中,我们将借助示例学习 Java 断言(Java 断言)。 Java 断言通过测试代码来检测错误,我们认为这是正确的。 使用`assert`关键字进行断言。 其语法为: ```java assert condition; ``` 在这里,`condition`是一个布尔表达式,我们假定在程序执行时为`true`。 * * * ## 启用断言 默认情况下,断言在运行时被禁用并被忽略。 为了启用断言,我们使用: ```java java -ea:arguments ``` 要么 ```java java -enableassertions:arguments ``` 启用断言且条件为`true`时,程序将正常执行。 但是,如果在启用断言的情况下条件求值为`false`,则 JVM 会抛出`AssertionError`,程序将立即停止。 * * * ### 示例 1:Java 断言 ```java class Main { public static void main(String args[]) { String[] weekends = {"Friday", "Saturday", "Sunday"}; assert weekends.length == 2; System.out.println("There are " + weekends.length + " weekends in a week"); } } ``` **输出** ```java There are 3 weekends in a week ``` 我们得到上面的输出,因为该程序没有编译错误,并且默认情况下,断言被禁用。 启用断言后,我们得到以下输出: ```java Exception in thread "main" java.lang.AssertionError ``` * * * ## 断言声明的另一种形式 ```java assert condition : expression; ``` 在这种形式的断言语句中,将表达式传递到`AssertionError`对象的构造器。 如果条件为`false`,则此表达式的值显示为错误的详细信息。 详细消息用于捕获和传输断言失败的信息,以帮助调试问题。 * * * ### 示例 2:带有表达式示例的 Java 断言 ```java class Main { public static void main(String args[]) { String[] weekends = {"Friday", "Saturday", "Sunday"}; assert weekends.length==2 : "There are only 2 weekends in a week"; System.out.println("There are " + weekends.length + " weekends in a week"); } } ``` **输出**: ```java Exception in thread "main" java.lang.AssertionError: There are only 2 weekends in a week ``` 从上面的示例中可以看到,表达式被传递给`AssertionError`对象的构造器。 如果我们的假设是`false`并且启用了断言,则会抛出异常并附带一条适当的消息。 此消息有助于诊断和修复导致断言失败的错误。 * * * ## 对特定的类和包启用断言 如果我们不向断言命令行开关提供任何参数, ```java java -ea ``` 这将在除系统类之外的所有类中启用断言。 我们还可以使用参数为特定的类和包启用断言。 可以提供给这些命令行开关的参数为: **启用类名中的断言** 为了对程序`Main`的所有类启用断言, ```java java -ea Main ``` 要仅启用一个类, ```java java -ea:AnimalClass Main ``` 这仅允许在`Main`程序的`AnimalClass`中声明。 **启用包名称中的断言** 要仅启用包`com.animal`及其子包的断言, ```java java -ea:com.animal... Main ``` **启用未命名包中的断言** 要在当前工作目录中的未命名包中启用断言(当我们不使用`package`语句时)。 ```java java -ea:... Main ``` **启用系统类中的断言** 为了在系统类中启用断言,我们使用不同的命令行开关: ```java java -esa:arguments ``` OR ```java java -enablesystemassertions:arguments ``` 可以提供给这些开关的参数是相同的。 * * * ## 禁用断言 要禁用断言,我们使用: ```java java -da arguments ``` OR ```java java -disableassertions arguments ``` 要禁用系统类中的断言,我们使用: ```java java -dsa:arguments ``` OR ```java java -disablesystemassertions:arguments ``` 禁用断言时可以传递的参数与启用断言时相同。 * * * ## 断言的优点 1. 快速高效地检测和纠正错误。 2. 断言检查仅在开发和测试期间进行。 它们会在运行时自动删除在生产代码中,以免减慢程序的执行速度。 3. 它有助于删除样板代码并使代码更具可读性。 4. 重构和优化代码,以增强其正确运行的信心。 * * * ## 何时使用断言 ### 1.无法访问的代码 无法访问的代码是当我们尝试运行该程序时不会执行的代码。 使用断言来确保无法访问的代码实际上是不可访问的。 让我们举个例子。 ```java void unreachableCodeMethod() { System.out.println("Reachable code"); return; // Unreachable code System.out.println("Unreachable code"); assert false; } ``` 让我们再举一个不带默认大小写的`switch`语句示例。 ```java switch (dayOfWeek) { case "Sunday": System.out.println("It’s Sunday!"); break; case "Monday": System.out.println("It’s Monday!"); break; case "Tuesday": System.out.println("It’s Tuesday!"); break; case "Wednesday": System.out.println("It’s Wednesday!"); break; case "Thursday": System.out.println("It’s Thursday!"); break; case "Friday": System.out.println("It’s Friday!"); break; case "Saturday": System.out.println("It’s Saturday!"); break; } ``` 上面的`switch`语句指示星期几只能是上述 7 个值之一。 没有默认情况意味着程序员认为这些情况之一将始终被执行。 但是,在某些假设实际上是错误的情况下,可能尚未考虑某些情况。 应该使用断言来检查此假设,以确保未达到默认切换条件。 ```java default: assert false: dayofWeek + " is invalid day"; ``` 如果`dayOfWeek`的值不是有效天数,则会抛出`AssertionError`。 * * * ### 2.记录假设 为了记录其基本假设,许多程序员使用注释。 让我们举个例子。 ```java if (i % 2 == 0) { ... } else { // We know (i % 2 == 1) ... } ``` 请改用断言。 随着程序的增长,注释可能会过时和不同步。 但是,我们将不得不更新`assert`语句; 否则,它们也可能因有效条件而失败。 ```java if (i % 2 == 0) { ... } else { assert i % 2 == 1 : i; ... } ``` * * * ## 什么时候不使用断言 ### 1.公共方法中的参数检查 用户可以提供公共方法中的参数。 因此,如果使用断言来检查这些参数,则条件可能会失败并导致`AssertionError`。 不要使用断言,而要导致适当的运行时异常并处理这些异常。 * * * ### 2.计算影响程序运行的表达式 不要调用方法或求值可能在断言条件下影响程序操作的异常。 让我们以列表`weekdays`为例,该列表包含一周中所有天的名称。 ```java ArrayList weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" )); ArrayList weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" )); assert weekdays.removeAll(weekends); ``` 在这里,我们试图从工作日的`ArrayList`中删除元素`Saturday`和`Sunday`。 如果启用了断言,则程序可以正常运行。 但是,如果禁用了断言,则不会删除列表中的元素。 这可能会导致程序失败。 而是将结果分配给变量,然后使用该变量进行断言。 ```java ArrayList weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" )); ArrayList weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" )); boolean weekendsRemoved = weekdays.removeAll(weekends); assert weekendsRemoved; ``` 这样,无论断言是启用还是禁用,我们都可以确保从`weekdays`中删除所有`weekends`。 结果,它不会影响将来的程序操作。