有哪些真实的例子来理解断言的关键作用?


当前回答

Assert是一个关键字。它在JDK 1.4中引入。这是两种类型的断言

非常简单的断言语句 简单的断言语句。

默认情况下,所有assert语句都不会被执行。如果assert语句接收到false,则它将自动引发断言错误。

其他回答

断言用于检查后置条件和“永不失败”的前提条件。正确的代码应该永远不会使断言失败;当它们触发时,它们应该指出一个错误(希望是在接近问题的实际位置的地方)。

断言的一个例子可能是检查一组特定的方法是否以正确的顺序被调用(例如,在迭代器中hasNext()在next()之前被调用)。

断言主要用于调试应用程序,或者用于替换某些应用程序的异常处理,以检查应用程序的有效性。

断言在运行时工作。这里有一个简单的例子,可以非常简单地解释整个概念——assert关键字在Java中做什么?(WikiAnswers)。

这是另一个例子。我写了一个方法来查找两个排序数组中值的中位数。该方法假设数组已经排序。出于性能考虑,它不应该首先对数组排序,甚至不应该检查以确保它们已排序。然而,对未排序的数据调用此方法是一个严重的错误,我们希望在开发阶段尽早发现这些错误。下面是我处理这些看似矛盾的目标的方法:

public static int medianOf(int[] a, int[] b) {
  assert assertionOnlyIsSorted(a);      // Assertion is order n
  assert assertionOnlyIsSorted(b);
  ... // rest of implementation goes here. Algorithm is order log(n)
}

public static boolean assertionOnlyIsSorted(int[] array) {
  for (int i=1; i<array.length; ++i) {
    if (array[i] < array[i-1]) {
      return false;
    }
    return true;
  }
}

这样,缓慢的测试只在开发阶段执行,在开发阶段,速度没有捕获错误重要。您希望medianOf()方法具有log(n)性能,但“is sorted”测试是o (n)。因此,我将其放在断言中,以限制其在开发阶段的使用,并为其命名,以明确表示它不适合生产。

这样我就两全其美了。在开发过程中,我知道任何不正确地调用这个函数的方法都会被捕获并修复。而且我知道这样做的缓慢测试不会影响生产中的性能。(这也很好地说明了为什么要在生产环境中关闭断言,而在开发环境中启用断言。)

默认情况下,断言是禁用的。要启用它们,我们必须使用-ea选项运行程序(粒度可以改变)。例如,java -ea AssertionsDemo。

使用断言有两种格式:

简单:如。维护1 = = 2;//这将引发AssertionError。 更好的方法:断言1==2:“不可能..1不等于2”; 这将引发AssertionError,并显示给定的消息,因此更好。虽然实际的语法是断言expr1:expr2,其中expr2可以是返回值的任何表达式,但我更多地使用它只是为了打印消息。

下面是我在Hibernate/SQL项目的服务器中编写的断言。一个实体bean有两个有效的布尔属性,称为isActive和isDefault。每个都可以有一个值“Y”或“N”或null,被视为“N”。我们希望确保浏览器客户端仅限于这三个值。所以,在这两个属性的setter中,我添加了这样的断言:

assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;

注意以下几点。

This assertion is for the development phase only. If the client sends a bad value, we will catch that early and fix it, long before we reach production. Assertions are for defects that you can catch early. This assertion is slow and inefficient. That's okay. Assertions are free to be slow. We don't care because they're development-only tools. This won't slow down the production code because assertions will be disabled. (There's some disagreement on this point, which I'll get to later.) This leads to my next point. This assertion has no side effects. I could have tested my value against an unmodifiable static final Set, but that set would have stayed around in production, where it would never get used. This assertion exists to verify the proper operation of the client. So by the time we reach production, we will be sure that the client is operating properly, so we can safely turn the assertion off. Some people ask this: If the assertion isn't needed in production, why not just take them out when you're done? Because you'll still need them when you start working on the next version.

Some people have argued that you should never use assertions, because you can never be sure that all the bugs are gone, so you need to keep them around even in production. And so there's no point in using the assert statement, since the only advantage to asserts is that you can turn them off. Hence, according to this thinking, you should (almost) never use asserts. I disagree. It's certainly true that if a test belongs in production, you should not use an assert. But this test does not belong in production. This one is for catching a bug that's not likely to ever reach production, so it may safely be turned off when you're done.

顺便说一句,我可以这样写:

assert value == null || value.equals("Y") || value.equals("N") : value;

对于只有三个值是可以的,但是如果可能值的数量变大,HashSet版本就会变得更方便。我选择HashSet版本来说明我关于效率的观点。