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


当前回答

断言是可以被关闭的检查。它们很少被使用。为什么?

它们不能用于检查公共方法参数,因为您无法控制它们。 它们不应该用于简单的检查,如result != null,因为这样的检查非常快,几乎没有什么可以保存。

那么,还剩下什么呢?昂贵的条件检查是真实的。像rb树这样的数据结构的不变量就是一个很好的例子。实际上,在JDK8的ConcurrentHashMap中,对于TreeNodes有一些这样有意义的断言。

您确实不希望在生产环境中启用它们,因为它们很容易控制运行时间。 您可能希望在测试期间打开或关闭它们。 在处理代码时一定要打开它们。


有时候,支票不是很贵,但与此同时,你很确定,它会通过。在我的代码中,有例如,

assert Sets.newHashSet(userIds).size() == userIds.size();

我很确定我刚刚创建的列表有独特的元素,但我想记录并再次检查它。

其他回答

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

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

断言(通过assert关键字)是在Java 1.4中添加的。它们用于验证代码中不变量的正确性。它们永远不应该在生产代码中触发,并且指示了代码路径的错误或误用。它们可以在运行时通过java命令上的-ea选项激活,但默认情况下不会打开。

一个例子:

public Foo acquireFoo(int id) {
  Foo result = null;
  if (id > 50) {
    result = fooService.read(id);
  } else {
    result = new Foo(id);
  }
  assert result != null;

  return result;
}

断言是可以被关闭的检查。它们很少被使用。为什么?

它们不能用于检查公共方法参数,因为您无法控制它们。 它们不应该用于简单的检查,如result != null,因为这样的检查非常快,几乎没有什么可以保存。

那么,还剩下什么呢?昂贵的条件检查是真实的。像rb树这样的数据结构的不变量就是一个很好的例子。实际上,在JDK8的ConcurrentHashMap中,对于TreeNodes有一些这样有意义的断言。

您确实不希望在生产环境中启用它们,因为它们很容易控制运行时间。 您可能希望在测试期间打开或关闭它们。 在处理代码时一定要打开它们。


有时候,支票不是很贵,但与此同时,你很确定,它会通过。在我的代码中,有例如,

assert Sets.newHashSet(userIds).size() == userIds.size();

我很确定我刚刚创建的列表有独特的元素,但我想记录并再次检查它。

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

使用断言有两种格式:

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

我不知道Java中这个特性背后的历史。但是我有一个关于断言可以用来做什么的想法,我认为在这个帖子中没有提到过。

假设你有一个枚举,你打开它:(†)

public enum Veggie {
    CAULIFLOWER,
    CARROT,
}

// Another class
switch (veggie) {
    case CAULIFLOWER: value = 5;
    case CARROT: value = 3;
}

†:也许优秀的Java编译器/工具会静态地捕获丢失的枚举值。在这种情况下,想象一下你发现了一些bug并修复了它。然后,您可以使用下面描述的技术在代码中适当地添加回归测试。


这里没有好的默认情况。所以你要确保你覆盖了所有的值。当你添加一个新的enum变量时,你要确保你更新了switch块:

public enum Veggie {
    CAULIFLOWER,
    CARROT,
    TOMATO,
}

但事实证明,当用户在web应用程序中加载特定视图时,这段代码会被调用。尽管存在这个错误,视图仍然可以持续存在:这将是一个bug,但不值得干扰视图的加载(让我们说用户只是看到了一些错误的数字)。所以你只需要记录一个警告:

switch (veggie) {
    case CAULIFLOWER: value = 5;
    case CARROT: value = 3;
    default: nonExhaustiveMatchOnEnum();
// […]
public static void nonExhaustiveMatchOnEnum() {
    String errorMessage: "Missing veggie";
    logger.warn(errorMessage);
}

但是当你在开发代码时,你确实希望这个错误立即失败——开发者可以在五分钟内修复这个错误,而不像你的web应用程序的用户。

所以你可以添加一个assert false:

public static void nonExhaustiveMatchOnEnum() {
    String errorMessage: "Missing veggie";
    assert false : errorMessage;
    logger.warn(errorMessage);
}

现在,应用程序将在本地崩溃,但只在生产中记录一个警告(假设您在本地使用java -ea,而不是在生产中)。