58.md 7.7 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
# 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");
  }
} 
```

**Output**

```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"; 
```

W
wizardforcel 已提交
266
如果`dayOfWeek`的值不是有效天数,则会抛出`AssertionError`
W
wizardforcel 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

* * *

### 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.计算影响程序运行的表达式

W
wizardforcel 已提交
311
不要调用方法或求值可能在断言条件下影响程序操作的异常。
W
wizardforcel 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

让我们以清单`的平日`为例,该清单包含一周中所有天的名称。

```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; 
```

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