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


当前回答

下面是我在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版本来说明我关于效率的观点。

其他回答

下面是最常见的用例。假设你正在打开一个枚举值:

switch (fruit) {
  case apple:
    // do something
    break;
  case pear:
    // do something
    break;
  case banana:
    // do something
    break;
}

只要你处理每一个案子,就没问题。但是有一天,有人会把fig添加到你的枚举中,而忘记把它添加到你的switch语句中。这将产生一个难以捕捉的错误,因为直到您离开switch语句后才会感受到其影响。但是如果你像这样写开关,你可以立即捕获它:

switch (fruit) {
  case apple:
    // do something
    break;
  case pear:
    // do something
    break;
  case banana:
    // do something
    break;
  default:
    assert false : "Missing enum value: " + fruit;
}

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

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

Assert在开发时非常有用。当代码正常工作时,某些事情就不能发生。它易于使用,并且可以永远保留在代码中,因为在现实生活中它将被关闭。

如果这种情况在现实生活中有任何可能发生,那么您必须处理它。

我喜欢它,但不知道如何在Eclipse/Android/ADT中打开它。即使在调试时,它也似乎是关闭的。(有一个关于这个的线程,但它指的是“Java虚拟机”,它不会出现在ADT运行配置中)。

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

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

基本上,“断言为真”会通过,“断言为假”会失败。让我们看看这是如何工作的:

public static void main(String[] args)
{
    String s1 = "Hello";
    assert checkInteger(s1);
}

private static boolean checkInteger(String s)
{
    try {
        Integer.parseInt(s);
        return true;
    }
    catch(Exception e)
    {
        return false;
    }
}