23

我看到了Java 7,他们介绍了方法Objects.requireNonNull(T obj, String message)

检查指定的对象引用是否不为空,NullPointerException如果是,则抛出自定义。此方法主要设计用于在具有多个参数的方法和构造函数中进行参数验证。

在开始重新格式化我的代码之前,我会在这里询问有关使用它的一些反馈。

 public Foo(Bar bar, Baz baz) {
         /** Old one
         this.bar = bar;
         this.baz = baz;
         **/
         this.bar = Objects.requireNonNull(bar, "bar must not be null");
         this.baz = Objects.requireNonNull(baz, "baz must not be null");
   }

当我构造我的对象时直接使用它是更好的做法吗(我在考虑是否为开发人员创建一个库或其他东西)?

还是我应该将其保留为“经典/旧”构造函数?

4

3 回答 3

11

如您所见,是否应该抛出 NPE 或其他异常存在分歧1

如果您接受 NPE 比替代方案更合适,并且这种情况null明显不正确,那么:

  • 最好早点扔NPE;即在构造函数中,和
  • 最好用自定义异常消息抛出它;即null当 JVM 抛出 NPE 时不会发生这种情况。

在这种情况下,使用Objects.requireNonNull显然是一种很好的做法。


您也可以为此使用 Java 断言,但您需要判断是否可以关闭测试是好事还是坏事。您必须考虑关闭提前检查所带来的性能优势是否超过了不提前检查可能导致的问题。例如,假设您在生产中看到一个 NPE 关闭了断言......并且您无法诊断它。你打开断言吗?断言会改变代码的行为吗?它会减慢您的系统速度(由于许多其他断言检查)吗?触发 NPE 的情况是否可能再次发生?

(与线程相关的错误通常是“千载难逢”的事情,非常难以重现。我认为您需要信息来诊断问题的任何时候......不仅仅是当您有断言时检查已启用。)


向后兼容的论点可能是相关的。但是,作为一般规则,您不会编写代码以在旧的 Java 平台上运行。如果您有支持旧版本 Java 的特定要求……那就不同了。但如果是这种情况,您根本不应该针对 Java 7 API 进行开发……所以您的编译器/IDE 应该将该Objects类标记为编译错误。

(限制自己只在不需要时使用较旧的 API,这会使您的代码质量受到影响,并使其更早“过时”。新东西的全部意义在于使编写可靠/可维护的代码变得更容易应用程序。故意不使用它是...不正常的。想象一下,如果您将自己限制在 Java 1.1 ...)


1 - FWIW,我认为 NPE 很好。并且带有消息的 NPE 比 (say) 更具体IllegalArgumentException,并且在 Java 标准类库中有很多用于构造函数等的先例,这些先例被记录为抛出 NPE。此外,这种方法显然是为这种方式使用而设计的。

于 2013-05-07T22:41:02.833 回答
9

我对requireNonNull()抛出NullPointerException. 在我看来,抛出经典IllegalArgumentException让意图更加清晰。人们也可以使用Assertions它们,其优点是它们可以有选择地打开和关闭。

最重要的是,如果您想将代码作为库公开,通常应该努力支持最旧的 JDK。

编辑:今天我想添加任何众所周知的框架,您会发现他们的 API 总是会抛出名称如此描述性的异常,您几乎可以立即知道出了什么问题。

举个例子,当一个 Spring 容器发现@Required托管 bean 上的一个属性不能被注入并因此保持不变时会发生什么NULL。您当然不会得到NullPointerException尽可能描述性的错误消息。

你会得到一个关于成员变量BeanCreationExceptionBeanInitializationException进一步信息,这些信息仍然null在描述性足够的错误消息中,例如:bean 'circle' 需要属性'center'。

于 2013-05-07T22:31:48.460 回答
0

如果您碰巧有barand的设置器baz,您应该在设置器中执行此操作:

public Foo(Bar bar, Baz baz) {
    setBar(bar);
    setBaz(baz);
}

public void setBar(Bar bar) {
    this.bar = Objects.requireNonNull(bar, "bar must not be null");
}

public void setBaz(Baz baz) {
    this.baz = Objects.requireNonNull(baz, "baz must not be null");
}

否则你展示的方法很好。

关于这样做的问题 - 如果您的对象在bar并且baz为空时完全无用,您不妨在构造函数和设置器处进行空检查。但是,如果您的对象可以在它们为空时使用 - 即使该用法只是检查它们是否为空并使用设置器设置它们,假设这是您的类的合法使用 - 那么您可以让您的用户这样做。

于 2013-05-07T22:28:30.627 回答