前提条件库为非空检查

时间:2015-05-04 20:00:28

标签: java nullpointerexception guava apache-commons preconditions

你知道Apache Commons ValidateGuava Preconditions的一个不错的替代方案,当检查对象是否为 not null 时,会抛出IllegalArgumentException而不是NullPointerException(Spring Assert除外) ?

我知道Javadocs说:

  

应用程序应抛出此类的实例[NullPointerException]以指示其他类   非法使用null对象。

尽管如此,我只是不喜欢它。对我来说,NPE总是意味着我只是忘了在某个地方获得null引用。我的眼睛是如此受过训练,我可以发现它以每秒几页的速度浏览日志,如果我这样做,那么我的头脑中始终会启用bug警报。因此,如果我把它抛到我预期的IllegalArgumentException,那将是非常令人困惑的。

说我有一个豆子:

public class Person {
  private String name;
  private String phone;
  //....
}

和服务方法:

public void call(Person person) {
  //assert person.getPhone() != null
  //....
}

在某些情况下,一个人没有电话可能没问题(我的奶奶没有电话)。但是,如果你想打电话给这样的人,对我而言,它会调用调用方法并传递 IllegalArgument 。查看层次结构 - NullPointerException甚至不是IllegalArgumentException的子类。它基本上告诉你 - 再次尝试在空引用上调用getter。

此外,已经有讨论,我完全支持this很好的答案。所以我的问题只是 - 我是否需要做这样丑陋的事情:

Validate.isTrue(person.getPhone() != null, "Can't call a person that hasn't got a phone");

以我的方式,或者是否有一个库只会抛出IllegalArgumentException进行notNull检查?

7 个答案:

答案 0 :(得分:7)

由于这个问题的主题演变为“正确使用IllegalArgumentException和NullpointerException”,我想指出有效Java项目60(第二版)中的海峡前瞻性答案:

  

可以说,所有错误的方法调用归结为非法论证   或非法国家,但其他例外标准用于某些类型的非法   论点和状态。 如果调用者在某些参数中为null值传递null   禁止,约定规定抛出NullPointerException   而不是IllegalArgumentException 。同样,如果呼叫者超出范围   表示序列索引的参数中的值,IndexOutOfBoundsException   应该抛出而不是IllegalArgumentException。

答案 1 :(得分:5)

Preconditions' s checkArgument怎么办?

public void call(Person person) {
    Preconditions.checkArgument(person.getPhone() != null);
    // cally things...
}

checkArgument throws IllegalArgumentException代替NullPointerException

答案 2 :(得分:1)

您可以将valid4j与hamcrest-matchers一起使用(在Maven Central上找到org.valid4j:valid4j)。验证' class支持常规输入验证(即抛出可恢复的异常):

import static org.valid4j.Validation.*;

validate(argument, isValid(), otherwiseThrowing(InvalidException.class));

链接:

侧面说明:此库还支持前置和后置条件(如断言),如果需要,可以注册自己的自定义全局策略:

import static org.valid4j.Assertive.*;

require(x, greaterThan(0)); // throws RequireViolation extends AssertionError
...
ensure(r, notNullValue()); // throws EnsureViolation extends AssertionError

答案 3 :(得分:1)

看看https://bitbucket.org/cowwoc/requirements(我是作者)。您可以使用withException()覆盖默认异常类型,如下所示:

new Verifiers().withException(IllegalArgumentException.class).requireThat(name, value).isNotNull();

答案 4 :(得分:0)

不是我意识到的。我只是通过简洁的调用来实现您想要的行为,模仿Guava的实现,但调整了异常类型。

class Preconditionz {
    public static <T> T checkNotNull(T reference, Object errorMessage) {
        if (reference == null) {
            throw new IllegalArgumentException(String.valueOf(errorMessage));
        }
        return reference;
    }
}

我喜欢继续import static这些经常使用的方法,所以你可以超级简洁地称呼它们。

import static com.whatever.util.Preconditionz.checkNotNull;

// ...

public void call(Person person) {
    checkNotNull(person, "person");
    checkNotNull(person.getPhone(), "person.phone");
    // ...
}

根据您的环境,您可能需要将其命名为checkNotNull2,以便在IDE中通过自动完成功能添加导入更容易,或者让您将其与标准checkNotNull一起使用。

答案 5 :(得分:0)

由于OlivierGrégoire,Louis Wasserman,CollinD和Mantain Man的好评,我想我在这里再次学到了一些东西。 这些标准通常是一个强大而充分的理由,因为它们使得公共语言程序员总能正确理解,但在这个特殊情况下,我有一点疑问,也许这个围绕NPE设置的规则并不太好。 Java是一种古老的语言,它的一些功能有点不吉利(我不想说错,这可能是太强烈的判断) - 就像checked exceptions,尽管你也可能不同意。现在我认为这个疑问已经解决了,我应该:

  • 在特定上下文中抛出IllegalArgumentException,我可以从业务角度告诉为什么null值是错误的。例如,在服务方法public void call(Person person)中,我知道系统对电话号码为空意味着什么。
  • 当我只知道这里的null值是错误的并且迟早会导致NullPointerException时抛出NullPointerException,但在特定的上下文中我不知道从业务角度来看它意味着什么。例子是Guavas不可变集合。当你构建这样的并尝试添加一个null值的元素时,它会抛出一个NPE。它不明白这个值对你来说意味着什么,它太通用了,但它只是知道它在这里是错误的,所以它决定立即告诉你,用一些更合适的信息,这样你就能更有效地认识到这个问题。 / LI>

考虑到上述情况,我会说在public void call(Person person)示例中做出断言的最佳选择就像Man船长建议的那样:

Preconditions.checkArgument(person.getPhone() != null, "msg");

检查参数是这个方法的一个好名字 - 显然我正在检查业务合同是否符合person参数,而且很明显,如果失败,我期待IllegalArgumentException。这是一个比Apache Commons的Validate.isTrue更好的名字。另一方面,说Validate.notNull或Preconditions.checkNotNull表明我正在检查空引用,我实际上是在期待NPE。

所以最终的答案是 - 没有这样的漂亮的库,不应该因为这会令人困惑。 (并且应该纠正Spring断言)。

答案 6 :(得分:-1)

您可以轻松地执行此操作:

if (person.getPhone() == null) {
    throw new IllegalArgumentException("Can't call a person that hasn't got a phone");
}

其他程序员很清楚你的意思,并且完全符合你的要求。