# 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<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ));

ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" ));

assert weekdays.removeAll(weekends); 
```

在这里，我们试图从工作日的`ArrayList`中删除元素`Saturday`和`Sunday`。

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

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

```java
ArrayList<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ));

ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" ));

boolean weekendsRemoved = weekdays.removeAll(weekends);
assert weekendsRemoved; 
```

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