是否应该在生产代码中使用断言语句断言不为 null?[已关闭]

2022-09-01 06:36:22

我已经看到了这个问题,但对关键字的用法还有一些问题。我正在与其他一些编码人员讨论使用.对于此用例,有一个方法可以在满足某些先决条件时返回 null。我编写的代码调用该方法,然后断言它不返回 null,并继续使用返回的对象。assertassert

例:

class CustomObject {
    private Object object;

    @Nullable
    public Object getObject() {
        return (object == null) ? generateObject() : object;
    }
}

现在想象一下,我是这样使用它的:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    assert object != null;
    // Do stuff using object, which would throw a NPE if object is null.
}

我被告知我应该删除 ,它们永远不应该在生产代码中使用,而只能在测试中使用。这是真的吗?assert


答案 1

使用 Objects.requireNonNull(Object) 来实现这一点。

检查指定的对象引用是否不为 null。此方法主要用于在方法和构造函数中进行参数验证, [...]

在你的情况下,这将是:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    Objects.requireNonNull(object); // throws NPE if object is null
    // do stuff with object
}

此函数是为您要执行的操作而创建的:显式标记不执行的操作。这样做的好处是,您可以在不应出现值的位置找到 -值。调试由 s 引起的问题时,您将遇到更少的麻烦,这些问题被传递到不应该传递到的位置。nullnullnull

与 相比,使用此功能时的另一个好处是灵活性。虽然是用于检查布尔值的关键字,但却是一个函数,可以更容易地嵌入到代码中。assertassertObjects.requireNonNull(Object)

Foo foo = Objects.requireNonNull(service.fetchFoo());

// you cannot write it in one line.
Bar bar = service.fetchBar();
assert bar != null;
service.foo(Objects.requireNonNull(service.getBar()));

// you cannot write it in one line.
Bar bar = service.getBar();
assert bar != null;
service.foo(bar);

请记住,这仅用于检查,而用于一般断言。因此有不同的目的:主要是测试。必须启用它,以便您可以启用它进行测试并在生产中禁用它。使用它来将仅测试测试与测试(或者更确切地说是检查)分开,测试也适用于生产代码。Objects.requireNonNull(Object)nullassertassert


答案 2

关于断言,要记住的最重要的事情是它们可以被禁用,所以永远不要假设它们将被执行。

为了向后兼容,JVM 缺省情况下禁用断言验证。必须使用 -enableassertions 命令行参数或其速记 -ea 显式启用它们:

java -ea com.whatever.assertion.Assertion

因此,依赖它们不是一个好的做法。

由于默认情况下不启用断言,因此您永远不能假设它们在代码中使用时会执行。因此,您应该始终检查空值和空 Optionals,避免使用断言来检查公共方法中的输入,而是使用未经检查的异常...通常,执行所有检查,就好像断言不存在一样。


推荐